HTTP Verb Tampering — Prevention
Two root causes: insecure server configurations and insecure application code. Both must be addressed.
Insecure Configuration
HTTP Verb Tampering vulnerabilities occur when authorization is limited to specific HTTP verbs, leaving remaining methods unprotected. This affects all major web servers.
Vulnerable Apache Configuration
Found in site config (e.g., 000-default.conf) or .htaccess:
<Directory "/var/www/html/admin">
AuthType Basic
AuthName "Admin Panel"
AuthUserFile /etc/apache2/.htpasswd
<Limit GET>
Require valid-user
</Limit>
</Directory>
<Limit GET> restricts auth to GET only — POST, HEAD, OPTIONS, etc. are all unprotected. Even listing both GET and POST still leaves other methods open.
Vulnerable Tomcat Configuration
Found in web.xml:
<security-constraint>
<web-resource-collection>
<url-pattern>/admin/*</url-pattern>
<http-method>GET</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<http-method>GET</http-method> limits authorization to GET only.
Vulnerable ASP.NET Configuration
Found in web.config:
<system.web>
<authorization>
<allow verbs="GET" roles="admin">
<deny verbs="GET" users="*">
</deny>
</allow>
</authorization>
</system.web>
allow and deny scoped to GET only.
Fixes
Rule: never restrict authorization to a specific HTTP method. Always allow/deny all verbs.
To specify a single method while covering all others, use safe keywords:
| Server | Safe keyword | What it does |
|---|---|---|
| Apache | LimitExcept | Covers all verbs except the specified ones |
| Tomcat | http-method-omission | Covers all verbs except the specified ones |
| ASP.NET | add/remove | Covers all verbs except the specified ones |
Additionally, consider disabling/denying all HEAD requests unless specifically required by the web application.
Insecure Coding
Harder to identify than config issues — requires finding inconsistencies in HTTP parameter usage across functions.
Vulnerable PHP Example
if (isset($_REQUEST['filename'])) {
if (!preg_match('/[^A-Za-z0-9. _-]/', $_POST['filename'])) {
system("touch " . $_REQUEST['filename']);
} else {
echo "Malicious Request Denied!";
}
}
This looks secure against command injection — preg_match properly blocks special characters. The fatal error is inconsistent HTTP method usage:
- The filter checks
$_POST['filename'] - The
system()call uses$_REQUEST['filename'](covers both GET and POST)
Attack: Send malicious input via GET. The $_POST parameter is empty (passes the filter), but $_REQUEST picks up the GET parameter and passes it to system() — command injection achieved.
In production, these inconsistencies are spread across the codebase (separate functions for validation and execution), making them much harder to catch.
Fixes
Rule: be consistent with HTTP methods. Use the same method for a given functionality across the entire application.
Expand the scope of security filters to test all request parameters:
| Language | Use this (covers all methods) |
|---|---|
| PHP | $_REQUEST['param'] |
| Java | request.getParameter('param') |
| C# | Request['param'] |
If security-related functions cover all methods, verb tampering bypasses are eliminated.