4 ms·
The Rust println! macros interpret the format string at compile time. You cannot do: let f = "{:.3}"; println!(f, 3.145); because then the macro cannot be
by meltedcapacitor 5y ago
The Rust println! macros interpret the format string at compile time. You cannot do:
let f = "{:.3}";
println!(f, 3.145);
because then the macro cannot be sure what the string will be at runtime and thus cannot be expanded.
Personally I dislike the whole idea of embedding sub-languages in strings inside host languages, but this is a lost cause frankly, and if one must do it, this is a pretty good way.
- pron 5y agoThe issue is that the format string does not require the variables to be sanitised. If the resulting string is then used the input to some sensitive operation, the operation no longer knows which parts of the string originated in the format string and which came from variables.
- ljm 5y agoMakes me think of tainted strings, a feature of Perl and Ruby (although I haven't often seen them used in Ruby).
- danhau 5y agoIsn’t that‘s just an input sanitization problem? If you chuck raw user input into some sensitive piece of code, you‘ve lost - doesn‘t matter whether its passed as a string or not. I don’t see how Rust‘s comptime string formatting is a pitfall here?
- tialaramex 5y agoSure, Rust does not require that your arbitrary string is actually safe HTML, a valid SQL string, XML element, DNS name and IPv4 address. As a result, if you take arbitrary input, and then run it as an SQL query who knows what will happen, despite it being a memory safe language. On the other hand, (safe) Rust has strong type checking, so you can make types named SafeHTML, ValidSQLString, XMLelement and so on, with the properties you desire enforced. This does not prevent the same idiots who try to make an SQL query using format!() from doing so, as they won't use ValidSQLString anyway. If all strings fill you with such fear, probably General Purpose Programming languages aren't for you, maybe you will feel safer in WUFFS. It looks at first glance as though WUFFS has strings, but it actually doesn't, they're just a human readable label for WUFFS non-OK statuses (e.g. errors like "#bad Huffman code"). You can rest assured that your WUFFS code for processing a PDF can't have SQL injection for two reasons: 1. WUFFS doesn't have any strings to inject SQL into, and 2. WUFFS can't talk to an SQL database at all. In exchange for this safety you give up the ability to do anything outside the tiny sphere of interest of the language.
- pron 5y agoStrings should fill you with fear, because the problem is not that they're supposed to be a major cause of vulnerabilities, or that they could be a major cause of vulnerabilities, but that they are a major cause of vulnerabilities. And the danger with this kind of string interpolation is that it makes using format! easier and so more attractive without making the creation of ValidSQLString easier.
- chucksmash 5y agoI see where you are coming from but I disagree with your conclusions. I think the number of developers who would not have insecurely built a SQL string from user input but for the language adding format strings is approximately zero. By analogy, to me this argument seems like saying, "If a standard library contains a StringBuilder class that minimizes unnecessary allocations when constructing a String, it encourages developers to construct SQL strings manually and therefore makes them more likely to fall victim to SQL injection attacks, therefore we must not provide StringBuilder classes." I don't imagine there are very many developers who are properly using parameterized queries only because it is inconvenient to concatenate strings.
- pron 5y ago> I think the number of developers who would not have insecurely built a SQL string from user input but for the language adding format strings is approximately zero. I'm not saying that format strings necessarily make injection vulnerabilities more common, but rather that, when added nowadays, they should be designed in a way that makes such vulnerabilities less common. If you're adding a feature that makes a potentially dangerous operation more convenient, you should also make it safer so that the convenience will help pull developers toward the safe option.
- drran 5y agoIMHO, your point is valid: currently, it's not possible to enforce a constraint on `format!()` arguments, AFAIK, so we cannot say that all arguments to that format string, which will be used in that API, must implement SafeHTML trait or SafeSQL trait. You should create a ticket or RFC for the problem.
- stubish 5y agoExactly like, say, string concatenation. String concatenation does not sanitize its arguments and can be misused to generate YAML, SQL, HTML, TOML in exactly the same way std::fmt can be misused. std::fmt is the wrong place for domain specific logic, as it is the sort of tool you need to write those domain specific APIs. Which you should be using instead of 'print' for your sensitive operations.
- pron 5y agoBut this feature need not necessarily be in std::fmt. It could be a more general language feature, with a pluggable formatting policy, which would then help improve the security of more specific libraries. That you shouldn't use unsafe string manipulation to do sensitive operations is obvious; the problem is that people do it anyway, which is why it is one of the most dangerous and common vulnerabilities.
- gpderetta 5y agoBut that would be true of any string operation, right? The correct solution is not to use strings with unknown content for sensitive operations (for example by having sensitive operations take a specially blessed string type).
- simias 5y agoIn my opinion that's a library problem, not a language problem. Creating code snippets at runtime by haphazardly concatenating strings is always going to be error-prone. Some SQL libraries use a builder pattern like, say: let result = Query::select().field("id").from("sometable").exec()?; I think that's superior to adding the concept of "sanitized" vs "unsanitized" string to the language, given that keeping track of this attribute robustly is going to be a pain IMO.
- drran 5y agoIMHO, this is the language problem. Rust can enforce correct types for all arguments to a function, except when type is erased by use of a generic container, like `String`. It's possible to enforce a `ValidHtmlLString` as argument to a function, with automatic conversion of a `String` into `ValidHtmlString` at runtime, but it doesn't protect from unsafe HTML, so `makeHeader(title: ValidHtml) -> ValidHtml` will happily accept `format!("<h1>{unsafeHtml}</h1>")` as argument. Maybe, we should create a specialized `format!()` macro, for example: `formatValidHtml!()`, `formatSafeHtml!()`, `formatAccessibleHtml!()`, or just a `formatRestricted!(ValidHtml + SafeHtml + AccessibleHtml, "<h1 role=\"banner\">{safeTitle}</h1>");`
- ape4 5y agoIs there another way to do that in Rust?
- speed_spread 5y agoNot as part of std but there are crates that do: https://crates.io/crates/strfmt https://crates.io/crates/strfmt https://crates.io/crates/runtime-fmt https://crates.io/crates/runtime-fmt