The Open Web Application Security Project is an online community founded in 2001 with the goal of improving software security.
As an organization, they release free penetation testing tools, write books on software security, and host user groups with chapters all around the world.
One of the major contributions OWASP makes to application security is the OWASP Top 10 Application Security Risks, a periodic survey of which application security risks are most prevalent.
The latest edition is 2017, with prior editions in 2013, 2010, 2007, and 2003. The authors combine data breach analysis, practitioner surveys, and the shared expertise of leaders in the field to distill the ten largest web application security risks at the present time.
Reviewing the top ten threats will help us get a bearing on what is happening in the industry today. Many of the top ten threats persist over time, indicating that these tend not to be ephemeral risks.
As a logistical note, covering ten threats means we will spend an average of five minutes per threat. This will limit how detailed we can get on any single threat, but I will have resources available if you wish to dig deeper into a particular topic.
SQL injection is the most common injection attack, but there are others, including LDAP injection, XPATH injection, CSV injection, etc.
Injection attacks are possible whenever we are building strings which include untrusted information in one context to execute in another context. This is most common when crossing language and tier boundaries.
SQL Injection attacks are a solved problem, yet they remain at the top of the OWASP Top 10 list because SQL injection is such an easy vector of attack and typically, websites with SQL injection vulnerabilities tend to have a host of other problems, including using sysadmin for application access and providing open access to sensitive information.
In this sense, the existence of SQL injection is an organizational bellwether: if it fails this extremely simple test, it likely has failed others.
The single best thing you can do to protect against SQL injection is to parameterize your queries. Non-terrible ORMs and stored procedures can both do this, though it is possible to misuse either. If you feel the urge to execute SQL passed in as a parameter, don't do it.
From there, whitelists work. Use whitelists to limit the domain of valid values (easy in the case of numeric or enumeration data types). Use regular expressions if it makes sense. These whitelists should be at every level you can think of: UI, backend application, and database. This is a case where defense in depth makes good sense.
Blacklisting particular words is not a good solution because industrious people will find ways around your blacklist.
You can also use a Web Application Firewall to intercept potentially malicious queries. These prevent many potential attacks from getting through but they are not perfect. It is possible to bypass Web Application Firewalls once you understand how they behave, but they will protect against the majority of noise.
If you want a more detailed analysis of SQL injection, I have a talk on the topic: https://CSmore.info/on/sqli. Or grab a copy of the book Tribal SQL, in which I contributed a chapter on SQL injection.
Broken authentication and session management includes flaws in the frameworks we use for authentication or session management. If an attacker is able to do something like access exposed accounts or passwords or hijack a session ID, that attacker can now impersonate a valid user.
A common example of poor authentication is keeping the session ID in the query string or as part of the URL. If this is your primary authentication mechanism, it's a bad idea because someday, one of your users will tweet a link to your site.
Store sensitive information in cookies rather than as part of the querystring or URL. It is possible to make the latter work securely but it involves a lot more work. ASP.Net defaults to use cookies only.
If you want to screw up, you can do so with this web.config setting:
Use tried and tested authentication methods rather than rolling your own. These are less likely to have major security vulnerabilities than code written by a team of non-specialists. In .NET, there is the ASP.Net MVC Identity system.
Add two-factor authentication (2FA). There are several NuGet packages which tie together the Microsoft Identity Framework and Google Authenticator. OWASP also has a tutorial on using one of them.
Find a good tradeoff between convenience and security with respect to timeouts. Leaving a person signed in longer is convenient, but expands the window that an attacker has to squirm into a session.
There are two timeout techniques: sliding window and fixed-length. Sliding window moves the expiration time back with every action. Fixed-length forces a hard stop, which you can change in web.config:
Encrypt sensitive data that you need to access later. This includes data in databases, configuration files, backups, extracts, etc.
For data that you don't need to access later (like plaintext passwords to your systems), keep a hash of the data. But don't use algorithms like MD5 or SHA1; they're fine for many uses, but not for secure password hashes.
Use strong adaptive algorithms for password storage. Use key derivation functions like PBKDF2 and password hashes like bcrypt, scrypt, or Argon2i. Use a large number of iterations with a good salt.
ASP.Net MVC 4 crypto uses PBKDF2 with 1000 iterations, but you cannot customize the number of iterations.
Zetetic has a NuGet package which uses BCrypt and 5000 iterations of PBKDF2.
Each method has its own weaknesses:
At its best, brute force is required to break hashing. With a good hash strategy (i.e., making hashing slow), it is not financially viable to perform a brute force attack.
The downside to slow hashing is that it's easier to perform a denial of service attack with mass login attempts.
Be sure to salt your hashes. A salt is a random set of bytes which are added to a password before it is hashed. You want a separate salt per hashed item.
Without a good hash + salt, an attacker can use a rainbow table, which is a reverse lookup from hash to plaintext.
When you need to encrypt data, know the difference between symmetric and asymmetric keys. Symmetric keys are good for internal data like credit card info, where the same machine encrypts and decrypts the data.
Asymmetric keys are good when you want different computers to communicate data back and forth.
Whichever you choose, secure the keys. Don't store them in source control or config files. Use the Data Protection API.
System.Security.Cryptography
has ProtectedData.Protect
and Unprotect
.
Valid scopes: CurrentUser
and LocalMachine
.
XML External Entity Injection (XXE) is an injection attack against XML parsers. It takes advantage of the XML spec, which allows for entities within XML. Entities are macros or placeholders that you can define in an XML file.
Those entities can also include filesystem files. XXE attacks happen when an attacker uses an XML External Entity to load data the attacker would otherwise not be able to access.
You've used entities before: & for ampersand, > and < for comparison operators, etc. Browsers support only a built-in set of XHTML entities.
Why don't browsers support custom XML external entities?
Our attack can take advantage of entities, specifically importation of external entities:
Safe by default:
XmlDictionaryReader
XmlNodeReader
XmlReader
XslCompiledTransform
Safe in .NET 4.5.2 or later and unsafe before:
XmlDocument
XmlTextReader
XmlPathNavigator
Safety here usually means prohibiting DTDs (Document Type Definitions). As of .NET 4.0, you have three options: prohibit DTDs and throw an exception if you receive a file with a DTD; ignore the DTD but parse the file otherwise; or parse the DTD.
You should never accept untrusted XML documents with DTDs. Unless you know the origin of the XML file and can ensure that there are no external entity references, you should ignore or prohibit DTDs.
Our attack can take advantage of entities, specifically importation of external entities:
Always explicitly prohibit DTDs, as that way you're sure to be safe. Don't rely on defaults.
This risk is that authorized users might be able to change parameters in your application and gain access to information that they were not authorized to see.
For example, if I see http://mysite.com/customers/32144, what happens when I try to go to /customers/32145? Or /customers/32143?
Or if I try IsAdmin=1?
With surrogate keys, use nonguessable values. Incrementing keys are great for database performance, but make it too easy for an end user to guess other people.
A solution here is indirect object references.
Build a reference map: translate a direct reference to an indirect reference (and vice versa).
You can use System.Security.Cryptography.RNGCryptoServiceProvider
to generate cryptographically random strings, and create a hashtable to support those translations back to your database keys.
Perform access control checks. Make sure the user is authorized to see this set of data. Don't assume that having a link is the same as having authorization to that data.
Indirect object references are a supplement; access control checks are the primary winner here.
Security misconfiguration is all about insecure configuration settings. As an example, leaving files with sensitive information accessible to the public would be misconfiguration--think password files, web.configs, etc.
You might also be displaying error messages with sensitive information: deployed code folders, internal source code, call stacks, framework/server versions, data sources and passwords, etc.
Good idea: using Elmah to store log data.
Bad idea: exposing Elmah data to the broader internet.
What's in your S3 bucket? There are thousands of public S3 buckets with interesting information like:
Rapid7 estimated in 2013 that one in six S3 buckets are available to the public. Many of those contain no sensitive information and are not risks, but some of them do have data their owners would rather not have generally available.
Set custom errors on:
(Or use RemoteOnly).
This creates a custom page and redirectMode hides that there was ever an error and never shows the end user that there was a 500 error. This will cause the web purists pain but prevents potential configuration exposure.
Secure trace.asd. Limit what you write to trace. For example, don't write connection strings to the trace. In web.config, you can easily turn it off:
In an administrative command prompt, run:
This uses the RSA key on the server to perform symmetric encryption on web.config's connection strings.
Cross-site scripting is where you get a user to execute unexpected code on a website. It is very similar to injection attacks, but focuses around JavaScript, CSS, or HTML rather than SQL, LDAP, etc.
There are two major themes with XSS: reflected and persistent.
Reflected XSS is where an attacker sends a modified link, adding malicious querystring data. Typically, the attacker distributes the link via e-mail, social media, and on forums. Without the link, a potential victim would not see XSS.
Persistent XSS is where an attacker is able to save malicious code in a database and have it appear without needing a reflection link.
There are several things you can do once you have exploited a Cross-Site Scripting vulnerability. You can run arbitrary scripts, access objects in the DOM, and even redirect unwary users to another site, such as a phishing site meant to harvest credentials.
Beat XSS with defense in depth. First, use an output encoding library. Microsoft has the Anti-XSS framework, which is built into .NET now: System.Web.Security.AntiXss
has AntiXssEncoder.HtmlEncode()
and HtmlDecode()
methods, as well as encoders and decoders for CSS, JavaScript, URLs, and XML.
NuGet also has the AntiXSS library, meant for old versions of the .NET Framework prior to when they built this in. This library can encode JavaScript, XML, LDAP, CSS, etc. code. For example:
If you're using ASP.NET MVC, the Razor view engine auto-encodes by default when you use @object
or Html.Encode()
. If you want to restore markup, use Html.Raw()
.
Whitelists are a viable solution, like with injection attacks. The encoding in the libraries above is a fancy form of whitelist, but you can build your own regular expressions as well to create custom whitelists.
Ever get this error?
.NET automatically validates page inputs and protects you against accepting potential malicious scripts...but it can be a little too aggressive, like throwing this `HttpRequestValidationException` on a password column with <
in it.
In general, you want these protections, so go to web.config and make sure to set:
But you might want to narrow that down a bit. You can do this at the page level:
In .NET 4.5 or later, you can enable or disable request validation for individual WebForms controls, like a password box.
For ASP.Net MVC, you can decorate model attributes to ignore enoding:
You can use the X-XSS-Protection
browser header to add an additional layer of protection against Cross-Site Scripting attack attempts. This works for pretty much every browser except Firefox.
You can use Content Security Policies to define valid domains and subdomains for:
Deserialization attacks came onto the scene in 2015, when security researchers found serialization vulnerabilities in Java. Attackers could perform remote code execution by sending serialized code to applications which use Java's "commons collections" library, a very popular library. Vulnerable applications included WebLogic, WebSphere, JBoss, Jenkins, etc.
Since then, we've learned that .NET applications are also vulnerable.
In .NET, Breeze and NancyFX had JSON deserialization flaws. There was also an XML deserialization flaw in DotNetNuke.
Breeze used Newtonsoft's JSON.Net parser (which is safe) in an unsafe way, using `TypeNameHandling.All` on an `Object` type:
If you deserialize into a FileSystemInfo
object and an attacker sends a string where part of the path begins with ~
(e.g., \\SomeServer\~MyShare
), then Windows automatically calls GetLongPathName()
on the string. If the path is a UNC path, Windows makes an SMB request, and an attacker might be able to perform SMB credential relaying if the attacker is on your local network.
Serialize data, not objects. If you have straight data in JSON or XML format and you prevent your deserializer from converting untrusted serialized inputs into objects, you should be safe.
Deserialize objects into specific defined types, ideally classes within custom assemblies. Don't deserialize to Object, IRunnable, or other low-level classes or interfaces. Sealed classes can help here.
Never deserialize untrusted binary objects.
Things to think about:
Maybe you should update that out-of-date version of Struts with known vulnerabilities before somebody goes and steals credit information for basically everybody in the United States.
Maybe you should update that out-of-date version of Wordpress with known vulnerabilities before somebody finds and pops your...too late.
Keep track of release notes for versions of libraries used. This can mean tracking mailing lists, GitHub pushes, NuGet package updates, and developer team blogs.
This can be a time-consuming exercise, particularly for large companies with a gigantic library surface area.
Gut check time:
.NET has a number of logging frameworks, including Elmah. You can also write out log messages to an external log collection process (Splunk, Logstash, Flume).
Think about high-value things to log: significant settings changes, transfers of funds, chains of failed login attempts followed by a successful attempt, and potential injection attacks. Log these as well as other things which might indicate an attacker or fraudulent behavior.
Simply having the data is an important part of the process. Then, somebody should read the log and understand what actions to take: investigate further, blackhole an IP address, etc.
Things you may want to log:
Details you should have:
This list is NOT comprehensive!
Details you should not have:
Include these and you might run afoul of A3. Sensitive Data Exposure.
This has been a quick survey of the OWASP Top 10 Application Security Risks, 2017 edition. Our examples focused on .NET but the top ten risks apply to all web platforms, although the specifics of protection mechanisms will naturally differ.
To learn more, go here:
https://csmore.info/on/owasp
And for help, contact me:
feasel@catallaxyservices.com | @feaselkl
Catallaxy Services consulting:
https://CSmore.info/on/contact