ASP.Net Security Checklist, Part 2

After securing our server and configuration, we can move on to our application.  ASP.Net comes in two flavors (soon to be three) flavors.  Web forms, a.k.a. “Let’s pretend web programming looks a lot like Windows!” came first, MVC came next.  Both have their strengths and weaknesses.  Here we shall focus on both their weaknesses.  That’s because our main application is a mix of both.  We are a small shop, so refactors tend to move at a dignified (some might say glacial) pace.  We replace pages one at a time, and often need to link a Web Forms page to a MVC page and vice versa.  So, we have to watch both frameworks for bad guys.  Enough prattling, on to the list.

 

Step 0. Authentication – This assumes you need to authenticate of course.  Our application allows anonymous browsing of the login page and…. that’s about it.  The application was originally written before forms authentication was released (yup, I am an oldster), so I came up with a ticket system that strongly resembles the flow of the aforementioned forms auth.  When we integrated MVC, we adapted the application to use the same functionality via attributes on controller actions (yes, again, before authorize filters were released).  In your case, if you have a choice, choose a built-in authentication method.  You are super smart, I know.  You are a crypto genius (me too!).  That said, there are a lot of people using the tools that come with .Net.  More eyeballs (allegedly) means defects surface quickly and can be corrected.  Conservative choices are boring, but usually correct.

 

Step 1. Username and passwords – Please use generic error messages.  If a login fails, do not tell the user why.  Generic errors prevent systematic probing (as painful as it sounds).  Progressively slowing down responses for failed logins also discourages bad behavior.  Based on my user demographic, locking accounts is a last resort for me, but still a valid tool.  Lastly, hash passwords.  Do not make them recoverable.  That’s just dumb.

 

Step 2. XSS – The most important thing in regards to defending again cross site scripting is to understand it.  Once you understand it: encode, scrub, rinse, repeat.  Use the built in tools at your disposal.  Encoding is baked into MVC pretty well.  There is the anti-xss library as well. If you can restrict your audience to modern browsers, check out the content security policy. Both Web forms and MVC provide request validation, make sure you are using it.

 

Step 3. CSRF – XSS’s ugly little brother.  Slightly more straightforward to defend against.

 

Step 4. Session Hijacking – See Part 1, Step 5.  SSL is your friend.  Don’t be cheap.

 

Step 5. Denial of Service – I feel a bit helpless when it comes to DDOS.  As a small shop with limited resources, it can be pretty tough to handle a DOS attack (we have never endured one, thankfully).  The only meaningful action you can take is to limit your request size and make sure your public pages are performant.  Logging (which you should be doing anyway) can help you trace the problem and maybe the attacker, but it is cold comfort in my opinion.

 

Step 6. SQL Injection – Use a SQL database?  Use parameterized queries (and scrub your input).  Don’t end up in a xkcd comic.

This checklist feels even more lightweight than the last one.  I think all I have accomplished is giving myself an anxiety attack.  Excuse me while I crawl under my desk and assume the fetal position.

ASP.Net Security Checklist, Part 1

A while back, I wrote a security checklist for SQL Server installations.  This time around, I would like to share my checklist for securing an ASP.Net application.  Securing a web application is a much more painful task than securing a database.  The attack surface is much larger. Web applications, by their nature, are open to the world.  They accept user input, files from outside sources, and anybody can connect to the server.  In part one we are focusing on the server itself and application configuration. Please note, this list is not comprehensive, hell it probably isn’t even very good, but it is what I do.

 

Step 0. Check your firewall – Please make sure you are only opening the ports you need.  Preferably, you should only have ports 80 and 443 open.  In reality, you probably also need to open ports for FTP, SMTP, or whatever, depending on what your application does.  Just make sure that, at minimum, the firewall is on and you are regularly checking the logs.  I ship all my logs into Azure table storage and peruse them regularly.  The web server logs, in particular, are always good for a chuckle.  They have some seriously smart ass port scanners on the interwebs.

 

Step 1. Run in a VM (even if you own the hardware) and keep a snapshot of your clean installation.  While this isn’t security per se, it does make recovering from oopsies less painful.

 

Step 2. Prune your processes – Look for applications and services you don’t need and disable them.  I like to use the Sysinternals tools for this job.

 

Step 3. Use least privilege – Please do not run your application under an admin account.  I did this in my younger days because I was too lazy to bother with ACLs and the like.  It was deeply stupid (like a lot of my ideas).  The server gods protected me like the lost, lobotomized child I was.  Don’t expect to be that lucky.  Now that I am slightly less brain damaged (dendrites grow back apparently), I like to create an account that is used only for the application.  I also use the same account for DB access; it makes administration a bit easier.  I grant the account access to exactly the files and folders it needs and do my best to isolate it from the server at large.  A PowerShell script (that you keep up to date) lessens the pain when you bring up a new installation, or change accounts.  If I run multiple installations on one server, I have an account per installation and keep installations as isolated from each other as possible.  You are less likely to make a mistake of the epic variety if your application is self-contained.

 

Step 4. Virus Protection? – Do you accept files?  If so, run virus protection.  Otherwise, use your best judgment.  Virus scanners are far from 100% secure, and there is a definite performance penalty.  However, that penalty is not nearly as severe as the penalty for infection.  Of course, the best route is to isolate your uploads on a separate server, if possible.

 

Step 5. Only use SSL – I can’t think of a single good reason for an application not run entirely under SSL these days.  The tubes can handle it.  Maybe you have reasons to send info via port 80. I hope they are good reasons.

 

Step 6. Encrypt your config – Preferably don’t store anything critical in your web.config file.  If you do, please encrypt it.  It is so easy to set up encryption a drunk panda (or me) can do it.  You should too.

 

Step 7. More config – While on the subject of the beloved web.config, please make sure debug config is turned off, custom errors are turned on, and you are limiting your request sizes.  It is just a good idea; there are bored, smart, and douchy people out there in the wild.

Seems like there should have been more steps.  I am going to check my servers.

Next time, securing your actual application!

SQL Server Security Checklist

Every so often, I like to review my SQL Server security settings and make sure they match current best practices.  I find that unless I build a checklist, I invariably forget something important.  It is worth mentioning that I will be skipping the obvious, like setting login passwords that a toddler can’t guess.

Before attempting to secure the database server, it makes sense to decide what it is you are trying accomplish.  Here is what I came up with:

  1.  Prevent the theft of the data.
  2.  Prevent unauthorized viewing of data.  Both on the server, and over the wire.
  3.  Prevent the unauthorized modification of data.
  4.  Secure the server from denial of service.

To accomplish these goals you need to:

  1. Prevent unauthorized access to the database, its files, and the OS.
  2. Secure the connection.
  3. Encrypt sensitive data.

Preventing Unauthorized Access Checklist

  1. Check for open firewall ports – 1433 is only port I need open.  I don’t have any named instances, so I have SQL Browser disabled and no dynamic ports are being used.  I also only open the ports for the client application IP addresses. The DB server cannot be reached from the open Internet.  In my particular case this is the best method for mitigating DoS threats on the DB end of things.
  2. Check SQL Server’s OS Account – I am currently using the MSSQLSERVER account.  It is specific to the application and has the minimum privileges needed to run the DB server.  It is a better option than Network Service, and especially better than Local System.
  3. Make sure no unnecessary accounts have access to the DB data and log folders.  My personal login, SQL Server, and administrators only have access.
  4. Make sure xp_cmdshell is disabled – I use the following query to check.  The result should be 0:
    SELECT value_in_use FROM sys.configurations WHERE name = 'xp_cmdshell'
  5. Guard against SQL Injection – Make sure to parameterize all your queries.  This is painful and slow and absolutely necessary.
  6. Make sure the client login has the least amount of privilege necessary.  Use a different login for each database, and only grant permission to objects when necessary for the proper functioning of the application.

Secure the Connection Checklist

  1. Encrypt the client connections – Ensure Force Encryption is turned on in SQL Configuration manager.  A self-signed certificate can be used, but you will need to explicitly trust the certificate in your client application.  You definitely want to use SSL in most environments as TDS packets are sent more or less in the clear.
  2. Use Channel Binding – Channel binding helps prevent man in the middle attacks by binding the encryption key generated by the client to that client.  There is a performance penalty to be paid here, so it is a tradeoff between performance and security that has to be decided on a case by case basis.

Encrypt Sensitive Data Checklist

  1. Hash passwords – This is just common sense, but passwords should be hashed and salted.
  2. Other data – Any piece of data for which the thought of its being stolen causes an immediate rise in blood pressure should be encrypted.  There are built-in tools in SQL Server that can handle this for you.  I use symmetric encryption and store the key on a different server.  It isn’t fool proof, but I like to think that even if someone gains access to the database server, hopefully they won’t also have the key.

This is hardly an exhaustive list, but it is the best a developer masquerading as a DB admin can conjure.  Just building the checklist is a great learning (and relearning) experience and I will come back every so often to update it as I pick up new information on possible attacks and freak out accordingly.