Wednesday, October 14, 2026

How to Protect an ASP.NET MVC Website from SQL Injection, XSS, and Malicious IIS Requests

 

Suspicious IIS logs can indicate automated vulnerability scanning against an ASP.NET MVC website. Common attack patterns include SQL injection, Cross-Site Scripting (XSS), server-side script injection, command injection, and attempts to discover vulnerable WordPress paths.

To protect your website, use multiple layers of security rather than relying only on a list of blocked strings.

1. Identify suspicious requests in IIS logs

Watch for patterns such as:

  • SQL injection expressions, including UNION SELECT, Boolean conditions, and database function calls.

  • XSS payloads containing HTML tags, JavaScript URLs, and event handlers such as onerror.

  • Server-side script injection attempts containing response.write or <% ... %> syntax.

  • Command injection attempts involving commands such as nslookup and curl.

  • Automated scans targeting paths such as /wp-admin, /wp-includes, and /wp-json.

These patterns indicate potentially malicious requests, but a matching log entry alone does not prove that an attack succeeded.

2. Configure custom deny-string rules

A custom deny-string list can help detect known malicious patterns. Example entries include:

<add string="union select" />
<add string="waitfor delay" />
<add string="information_schema" />
<add string="xp_cmdshell" />
<add string="dbms_pipe.receive_message" />
<add string="response.write(" />
<add string="&lt;script" />
<add string="&lt;iframe" />
<add string="&lt;img" />
<add string="onerror=" />
<add string="onload=" />
<add string="javascript:" />
<add string="data:text/html" />
<add string="nslookup" />
<add string="invoke-webrequest" />

These are examples, not a complete list of every possible attack. Your custom validation code must actually enforce these rules; adding them to an XML element alone does not automatically block requests in IIS.


<security>
    <requestFiltering>
        <!-- Increase the maximum allowed length for the query string and URL -->
        <requestLimits
            maxQueryString="116384"
            maxUrl="132768" />
        <!-- Block common SQL Injection patterns -->
        <filteringRules>
            <filteringRule
                name="BlockSQLInjection"
                scanUrl="false"
                scanQueryString="true">
                <appliesTo>
                    <clear />
                    <add fileExtension="." />
                </appliesTo>
                <denyStrings>
                    <clear />
                    <!-- =============================== -->
                    <!-- UNION-based SQL Injection       -->
                    <!-- =============================== -->
                    <add string="union select" />
                    <add string="union all select" />
                    <add string="union distinct select" />
                    <!-- =============================== -->
                    <!-- SQL expressions / conditions    -->
                    <!-- =============================== -->
                    <add string="convert(" />
                    <add string="cast(" />
                    <add string="case when" />
                    <add string="case" />
                    <add string="when" />
                    <add string="waitfor delay" />
                    <add string="waitfor time" />
                    <!-- =============================== -->
                    <!-- SQL comments                    -->
                    <!-- =============================== -->
                    <add string="--" />
                    <add string="/*" />
                    <add string="*/" />
                    <add string="#" />
                    <!-- =============================== -->
                    <!-- SQL execution                   -->
                    <!-- =============================== -->
                    <add string="declare" />
                    <add string="exec" />
                    <add string="execute" />
                    <!-- =============================== -->
                    <!-- SQL Server procedures/functions -->
                    <!-- =============================== -->
                    <add string="xp_cmdshell" />
                    <add string="xp_regread" />
                    <add string="xp_regwrite" />
                    <add string="xp_regdeletekey" />
                    <add string="xp_dirtree" />
                    <add string="xp_fileexist" />
                    <add string="sp_executesql" />
                    <add string="sp_oacreate" />
                    <add string="sp_oamethod" />
                    <add string="sp_oagetproperty" />
                    <add string="sp_oasetproperty" />
                    <!-- =============================== -->
                    <!-- External data access            -->
                    <!-- =============================== -->
                    <add string="openrowset" />
                    <add string="opendatasource" />
                    <add string="openquery" />
                    <add string="openxml" />
                    <!-- =============================== -->
                    <!-- Database/table modification     -->
                    <!-- =============================== -->
                    <add string="drop table" />
                    <add string="drop database" />
                    <add string="drop column" />
                    <add string="alter table" />
                    <add string="alter database" />
                    <add string="truncate table" />
                    <add string="insert into" />
                    <add string="delete from" />
                   
                    <!-- =============================== -->
                    <!-- Database enumeration            -->
                    <!-- =============================== -->
                    <add string="information_schema" />
                    <add string="sysobjects" />
                    <add string="syscolumns" />
                    <add string="sysdatabases" />
                    <add string="sys.tables" />
                    <add string="sys.columns" />
                    <add string="sys.objects" />
                    <add string="sysusers" />
                    <add string="systables" />
                    <!-- =============================== -->
                    <!-- Common boolean SQL injection    -->
                    <!-- =============================== -->
                    <add string="' or '" />
                    <add string="' and '" />
                    <add string="') or ('" />
                    <add string="') and ('" />
                    <add string="') or 1=1" />
                    <add string="' or 1=1" />
                    <add string="' and 1=1" />
                    <add string="or 1=1" />
                    <add string="and 1=1" />
                    <add string="or 1=0" />
                    <add string="and 1=0" />
                    <!-- =============================== -->
                    <!-- Common SQL functions             -->
                    <!-- =============================== -->
                    <add string="substring(" />
                    <add string="substring" />
                    <add string="charindex(" />
                    <add string="patindex(" />
                    <add string="ascii(" />
                    <add string="unicode(" />
                    <add string="len(" />
                    <add string="db_name(" />
                    <add string="user_name(" />
                    <add string="system_user" />
                    <add string="current_user" />
                    <add string="suser_name(" />
                    <add string="suser_sname(" />
                    <!-- =============================== -->
                    <!-- SQL Server version/database info -->
                    <!-- =============================== -->
                    <add string="@@version" />
                    <add string="@@servername" />
                    <add string="@@spid" />
                    <add string="@@language" />
                    <add string="@@servicename" />
                    <!-- =============================== -->
                    <!-- Common SQL operators/patterns   -->
                    <!-- =============================== -->
                    <add string="like '%" />
                    <add string="having 1=1" />
                    <add string="group by" />
                    <add string="order by" />
<!-- PowerShell command execution -->
    <add string="powershell" />
    <add string="invoke-webrequest" />
    <add string="invoke-restmethod" />
<add string="wp-admin" />
<add string="wp-includes" />
<add string="wordpress" />
<add string="wp-content" />
<add string="wp-json" />
                </denyStrings>
            </filteringRule>
        </filteringRules>
    </requestFiltering>
</security>

---------- all list ---------
<!-- ====================================== -->
<!-- SQL Injection: UNION Queries           -->
<!-- ====================================== -->
<add string="union select" />
<add string="union all select" />
<add string="union distinct select" />

<!-- ====================================== -->
<!-- SQL Injection: Execution and Delays    -->
<!-- ====================================== -->
<add string="waitfor delay" />
<add string="waitfor time" />
<add string="sp_executesql" />
<add string="xp_cmdshell" />
<add string="xp_regread" />
<add string="xp_regwrite" />
<add string="xp_regdeletekey" />
<add string="xp_dirtree" />
<add string="xp_fileexist" />
<add string="sp_oacreate" />
<add string="sp_oamethod" />
<add string="sp_oagetproperty" />
<add string="sp_oasetproperty" />

<!-- ====================================== -->
<!-- SQL Injection: Dynamic SQL and DDL     -->
<!-- ====================================== -->
<add string="declare" />
<add string="execute" />
<add string="convert(" />
<add string="cast(" />
<add string="drop table" />
<add string="drop database" />
<add string="drop column" />
<add string="alter table" />
<add string="alter database" />
<add string="truncate table" />
<add string="insert into" />
<add string="delete from" />

<!-- ====================================== -->
<!-- SQL Injection: External Data Access    -->
<!-- ====================================== -->
<add string="openrowset" />
<add string="opendatasource" />
<add string="openquery" />
<add string="openxml" />

<!-- ====================================== -->
<!-- SQL Injection: Database Enumeration    -->
<!-- ====================================== -->
<add string="information_schema" />
<add string="sysobjects" />
<add string="syscolumns" />
<add string="sysdatabases" />
<add string="sys.tables" />
<add string="sys.columns" />
<add string="sys.objects" />
<add string="sysusers" />
<add string="systables" />

<!-- ====================================== -->
<!-- SQL Injection: Boolean / Quote Patterns -->
<!-- ====================================== -->
<add string="' or '" />
<add string="' and '" />
<add string="') or ('" />
<add string="') and ('" />
<add string="' or 1=1" />
<add string="' and 1=1" />
<add string="or 1=1" />
<add string="and 1=1" />
<add string="or 1=0" />
<add string="and 1=0" />
<add string="having 1=1" />

<!-- ====================================== -->
<!-- SQL Injection: Comments and Operators  -->
<!-- ====================================== -->
<add string="--" />
<add string="/*" />
<add string="*/" />
<add string=" like '%" />

<!-- ====================================== -->
<!-- SQL Injection: Functions               -->
<!-- ====================================== -->
<add string="substring(" />
<add string="charindex(" />
<add string="patindex(" />
<add string="ascii(" />
<add string="unicode(" />
<add string="len(" />
<add string="db_name(" />
<add string="user_name(" />
<add string="system_user" />
<add string="current_user" />
<add string="suser_name(" />
<add string="suser_sname(" />
<add string="@@version" />
<add string="@@servername" />
<add string="@@spid" />
<add string="@@language" />
<add string="@@servicename" />
<add string="dbms_pipe.receive_message" />
<add string="from dual" />

<!-- ====================================== -->
<!-- SQL Injection: Expression Probes       -->
<!-- ====================================== -->
<add string="case when" />
<add string="case" />
<add string="when" />
<add string="group by" />
<add string="order by" />
<add string="chr(" />

<!-- ====================================== -->
<!-- Server-Side Script Injection           -->
<!-- ====================================== -->
<add string="response.write(" />
<add string="&lt;%" />
<add string="%3c%25" />

<!-- ====================================== -->
<!-- Cross-Site Scripting (XSS)              -->
<!-- ====================================== -->
<add string="&lt;script" />
<add string="%3cscript" />
<add string="&lt;iframe" />
<add string="%3ciframe" />
<add string="&lt;img" />
<add string="&lt;body" />
<add string="&lt;isindex" />
<add string="&lt;!--" />
<add string="--&gt;" />
<add string="onerror=" />
<add string="onload=" />
<add string="javascript:" />
<add string="data:text/html" />

<!-- ====================================== -->
<!-- External XSS Testing Services           -->
<!-- ====================================== -->
<add string="bxss.me" />
<add string="attacker-" />

<!-- ====================================== -->
<!-- Command Injection                      -->
<!-- ====================================== -->
<add string="nslookup" />
<add string="curl" />
<add string="powershell" />
<add string="invoke-webrequest" />
<add string="invoke-restmethod" />

<!-- ====================================== -->
<!-- WordPress Scanning                      -->
<!-- ====================================== -->
<add string="wp-admin" />
<add string="wp-includes" />
<add string="wp-content" />
<add string="wp-json" />
<add string="wordpress" />

3. Do not rely on exact-string matching

Attackers can change numbers, capitalization, whitespace, quotation marks, comments, and URL encoding to bypass exact matches.

For example, blocking one mathematical expression such as 5*5=25 will not detect every variation. Use suitable pattern-based detection, normalize encoded input safely, and validate values according to the expected format of each parameter.

Avoid broad deny strings that could reject legitimate customer input. Test new rules against normal website traffic before deploying them to production.

4. Validate input using allowlists

For an ASP.NET MVC application, validate every parameter according to its purpose.

  • Product and product type: Accept only supported product names and types.

  • Quantity: Require a positive integer within a reasonable business limit.

  • Platform: Accept only recognized platform values.

  • Download parameters: Accept only supported product and platform combinations.

Validation must happen on the server, even if the same fields are validated in JavaScript.

5. Use parameterized SQL queries

Parameterized queries are a primary defense against SQL injection. Never build SQL statements by concatenating untrusted request values.

For Entity Framework, prefer LINQ queries or properly parameterized database commands. Avoid executing dynamically constructed SQL from user input.

6. Prevent Cross-Site Scripting

Use context-aware output encoding when displaying user-controlled data. In ASP.NET MVC Razor views, prefer normal encoded expressions such as:

@Model.CustomerName

Avoid rendering untrusted input with Html.Raw() unless it has been safely sanitized for the intended HTML context.

7. Use IIS Request Filtering and a Web Application Firewall

IIS Request Filtering can reject malformed requests and restrict unwanted URL sequences, file extensions, and request sizes. A Web Application Firewall (WAF) can provide additional detection for common attack patterns.

These controls complement application-level validation; they do not replace secure coding practices.

8. Investigate HTTP status codes and application errors

A suspicious request returning HTTP 200 does not necessarily mean that the payload executed. Similarly, a 302 redirect does not prove that the request was blocked.

Review application logs and exception details for HTTP 500 responses, verify the behavior of affected endpoints, and check whether unexpected database operations or changes occurred.

Conclusion

Protecting an ASP.NET MVC website requires layered security: safe SQL access, strict server-side input validation, output encoding, appropriate IIS filtering, and monitoring of suspicious requests. Custom deny-string rules are useful as an additional layer, but they cannot guarantee protection against every attack variation.