I decided to go with a very simple CGI user registration program to pair with Apache's mod_auth_form
wrapper around a private site. It was only just after I finished writing that I realized I'd written security-sensitive code in a language I'm not my best at.
Is this code secure from parameter injection attacks? I.e., if the attacker fiddles with the POST values, can they run arbitrary commands on the server as the web server user?
#!/bin/bash
echo "Content-type: text/html"
echo ''
cat <<EOT
<!doctype html>
<html>
<head>
<title>Registered</title>
<link rel="icon" href="/favicon.png">
</head>
<body>
EOT
POST=$(cat)
if [ "$REQUEST_METHOD" != "POST" ] || [ ! "$POST" ]; then
echo "<h1>Error</h1><p>Please go back and try again</p></body></html>";
exit 1;
fi
function input {
echo "$POST" | sed 's/^.*'"$1"'=\([^&]\+\)&.*$/\1/' | python -c "import sys, urllib.parse as p; print(p.unquote(sys.stdin.read()));"
}
USERNAME=$(input username)
PASSWORD=$(input password)
PASSWORD2=$(input password2)
if [ "$PASSWORD" != "$PASSWORD2" ]; then
echo "<h1>Error</h1><p>Your passwords do not match.</p></body></html>";
exit 1;
fi
if [ ${#PASSWORD} -lt 10 ]; then
echo "<h1>Error</h1><p>Please pick a longer password.</p></body></html>";
exit 1;
fi
echo "$PASSWORD" | htpasswd -i ../registrations "$USERNAME"
cat <<EOT
<h1>You have registered</h1>
<p>Now, please email me so I can enable your account.</p>
</body>
</html>
EOT
exit 0
To clarify - I'm not concerned about the line of python
- it urldecodes/unescapes the field from the POST data and is extremely battle-tested. I put that in to avoid bugs/security concerns over other solutions with fewer dependencies (many with scary-looking bash constructs).
The sed
is also pretty straightforward - it pulls out the named parameter from the urlencoded POST data. &
is escaped as %26
and so will never show up in the input. I wrote/modified the sed
there and am confident enough that it'll behave as I expect (sed
is more familiar to me than bash
).
Essentially, please feel free to ignore the implementation of the input
function and assume it properly extracts POST variables into bash
variables. My concerns center entirely around whether that user supplied data (which can be essentially any sequence of bytes) in bash
variables will break or escape from any of the places I use it.