Version: v0.8.1 - Beta.  We welcome contributors & feedback.

TypeStrings

Background 

THT introduces TypeStrings as a method of preventing injection attacks.

What Are Injection Attacks?

Injection attacks are one of the top security vulnerabilities on the web.

This occurs when an attacker sends input containing meta-characters (e.g. quotes) which trick the app into executing something different from what was intended.

For example, here is a SQL query to check if a login was successful:

// Login query
select * from users
where user = 'admin'
and password = 'knock-knock'

An attacker could enter a malicious password that contains a quote, followed by some SQL code, like this:

// ✕ Malicious Input
knock-knock' or '1'='1
           ^

Here is what the query looks like with the malicious password. It allows the attacker to log in as any user in the system, because the query will always be true.

// ✕ Hijacked Query
select * from users
where user = 'admin'
and password = 'knock-knock' or '1'='1'

Attack Targets

Any subsystem is vulnerable to attack if it:

  1. Takes a string as input.
  2. Uses meta-characters to delineate data from code.

The most common targets are:

Subsystem Meta-characters
Database queries quotes, comments
HTML output angle brackets, quotes
System commands quotes

Sidebar: “Just Be Careful” (JBC) is Not Enough

Unfortunately, it’s not enough to “just be careful” and escape everything manually, for a few reasons:

In short, when working with thousands of lines of code, there are too many chances for even the most 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:

Altogether, this 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.

Examples:

$query = sql'select * from users where userId = {}'

$cmd = cmd'ls -l {}'

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;'
json JSON data json'{"a":[1,2,3]}'
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 

Nested 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>'

Nested Placeholders

TypeStrings can be nested in any combination.

When the top-level TypeString is rendered, all of the embedded TypeStrings will be rendered and escaped according to their type.

$colorHex = '#FF0000'
$css = css'color:{}'.fill($colorHex)

$userName = 'Admin'
$name = html'<b style="{}">{}</b>'.fill($css, $userName)

$name.renderString()
//= '<b style="#FF0000">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)

Template Functions 

Most TypeStrings have a corresponding Template Function that make it easy to create blocks of content that are safely parsed and escaped.

// Returns an HTML TypeString
tem headerHtml($userName) {

    <.welcome-banner>
        Welcome back, {{ $userName }}!
    </>
}

Methods 

See the TypeString class for a full list of methods.