TypeStrings
Background
TypeStrings are THT's approach to preventing injection attacks.
What Are Injection Attacks?
Injection attacks are the #1 security vulnerability on the web.
This occurs when an attacker sends input containing meta-characters (e.g. quotes) that trick the app into executing something different from what was intended.
For example, here is a SQL query to check a login attempt:
// Login query select * from users where user = 'admin' and password = 'knockknock'
An attacker could enter a malicious password that contains a quote, followed by some SQL code, like this:
// ✕ Malicious Input knockknock' or 1='1 ^--------
Here is what the query looks like with the new password. It allows the attacker to log in as any user in the system, because the query will always be true.
// ✕ Injection! select * from users where user = 'admin' and password = 'knockknock' or 1='1' ^--------
Attack Targets
Any subsystem is vulnerable to attack if it accepts strings that use meta-characters to embed data.
The most common targets are:
- Database queries (quotes, comments)
- HTML output (angle brackets, quotes)
- System commands (quotes)
Sidebar: “Just Be Careful” is Not Enough
Unfortunately, it’s not enough to “just be careful and escape everything manually”, for a few reasons:
- The programmer has to remember how each subsystem must be escaped.
- The programmer is human and can simply forget, or make a mistake.
- Strings are often mistakenly double-escaped.
- Strings that are safe now, can be made unsafe in the future by a change in another part of the code.
- An attacker only needs to find one mistake to render the whole system vulnerable.
In short, in thousands of lines of code, there are too many chances for even experienced programmers to overlook something.
How TypeStrings Work
To prevent injection attacks, THT introduces TypeStrings.
A TypeString is a literal string that is prefixed with a type identifier.
$query = sql'select * from table where userId = {}' ^^^
Placeholders
TypeStrings can ONLY be combined with plain, unprotected strings via the use of placeholders ({}
).
Placeholders (also known as parameterized queries) are an industry best practice for securing SQL queries by ensuring that all inserted data is safely escaped.
TypeStrings expand this tactic to cover all types of sensitive strings, like URLs, system commands, and HTML.
Why It Works
This approach is effective because:
- TypeStrings are literal constants hardcoded into your source files. This means you can trust them to be 100% benign. (Assuming you trust yourself!)
- High-risk modules only accept TypeStrings as input.
- TypeStrings automatically escape placeholders safely for their type.
Altogether, it removes human error from the equation, leading to more consistent protection with less effort.
How to Use TypeStrings
Just prepend the type to any literal string to mark it as a TypeString.
This tells THT to keep it separate from all other dynamic strings, which often come from outside (untrusted) sources.
Example:
$query = sql'select * from users'
Supported types:
Prefix | Description | Example |
---|---|---|
sql |
SQL query | sql'select * from posts' |
html |
HTML markup | html'<b>user123</b>' |
url |
URL | url'/posts?sort=desc' |
cmd |
System command | cmd'ls -l /some/path' |
js |
JavaScript code | js'var id = 123;' |
css |
CSS code | css'body { color: #333 }' |
lm |
Litemark markup | lm'# Contact Info' |
Filling Placeholder Values
You can attach dynamic values to a TypeString via the fill
method.
These will be inserted into placeholders (e.g. {}
), which will be safely escaped by the TypeString class.
$query = sql'select * from users where userId = {}' $query.fill($userId) // The Db module only accepts TypeStrings $row = Db.selectRow($query)
Combining TypeStrings
Embedded TypeStrings
If you insert a TypeString into another TypeString of the same type, it will be inserted verbatim.
$name = html'<b>Admin</b>' html'Posted by: {}'.fill($name) //= 'Posted by: <b>Admin</b>'
Appending TypeStrings
You can join two TypeStrings together using the stringy ~
operator.
Placeholder values must be filled separately before they are merged.
$query = sql'select title from posts where postDate > {}' $monthAgo = Date.create('30 days ago') $query.fill($monthAgo) // Append a dynamic 'limit' value $rowsPerPage = 20 $query ~= sql' limit {}'.fill($rowsPerPage)
Templates
Most TypeStrings have corresponding Template Functions that make it easy to create blocks of content that are safely and parsed and escaped.
// Returns an HTML TypeString tm headerHtml($userName) { <.welcome-banner> Welcome back, {{ $userName }}! </> }
Methods
See the TypeString class for a full list of methods.