Secure your website

Name: *
My email: *
Recipient email: *
Message: *
Fields marked as bold are compulsory.
You haven't filled in compulsory values. The email is not correct

When was the last time you heard a website was hacked? Well, probably what you have heard of concerned some major properly secure website and the people who got access to it were no rookies. However this is no excuse for you to stand there waiting for a novice hacker to play around with your website. Let's go through a few of the most common and easy to handle techniques.

 
 
web security
 

Getting Started

Web is a complicated thing.  There are a lot of ways a malicious user may attack you. Just because between you and him lies the web. A user can create false responses, create false cookies or try to get access to your database. To begin with let's keep in mind that what we will be talking about is not the security of your web server. This is a whole new topic responsible of which is your host and not you. However you are responsible for what you have created. No host will be sorry you for your deleted database tables if you were not careful enough with your code.
 
What's the whole idea of the attack? A nice way to attack a web application is to create unpredictable conditions. That is, to cause your server to throw an exception and send the attacker the exception details. You may think that this is no big deal and that even when you, who have written the code, take a look at an exception, there may be times you won't get what the problem is at once. So how could a stranger do so? That is absolutely not true. An attacker at first has no idea what your site code looks like. By getting exception messages he can slowly create an image of that.
 
exception message
 
So, a simple, yet great, step towards securing your website is to stop these messages. To do so, you should create an error page.
 
Creating an error page is a quite simple thing to do. It requires two things.
  1. Create a simple aspx page. It is a good thing to keep the same design as the rest of the site in case a user happens to find himself there, he will not feel alienated. Our simple error page will contain nothing more but the message              <b>This is the error page!</b>
  2. Set <customErrors mode="On" defaultRedirect="ErrorPageName.aspx"/> on your web.config file
 
error page
 
That's all. Now even though your attacker will know he did something bad, he will have no means to tell what effect this had.
 
 

Setting the scenery for our attacks

We will use a simple aspx page
 
Enter your username to log into our insecure website:
<asp:TextBox runat="server" ID="EvilTextBox" />
<asp:Button runat="server" ID="LogInButtonID" Text="Log In" OnClick ="LogInButtonClicked" />
<br />
<asp:Label runat="server" ID="ResultLabelID" />
 
Let's call it security.aspx
 
This is the code behind
 
protected void LogInButtonClicked(object sender, EventArgs e)
{
  //Get the text to enter in our sql query
  string evilTextBoxMessage = EvilTextBox.Text;
 
  string connectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
  SqlConnection con = new SqlConnection(connectionString);
  string sql = " SELECT * FROM TestMembers WHERE Username = '" + evilTextBoxMessage +"'";
 
  SqlCommand cmd = new SqlCommand(sql, con);
 
  con.Open();
  SqlDataReader reader = cmd.ExecuteReader();
  if (reader.HasRows)
    //Log the user
    ResultLabelID.Text = "Logged In. Welcome " + EvilTextBox.Text;
  else
    //Show failure message
    ResultLabelID.Text = "Could not log In. Username " + EvilTextBox.Text + "does not exist in the database.";
    reader.Close();
    con.Close();
 
}
 
I guess what it does is quite plain. We create an SqlCommand using the connection string we got from the web.config file. We open our connection, hit the database and then show the message. This would do perfect for a first database connection example but nothing more.
 
Let's see what may happen depending on the input.
 
1) A good user enters "Tom"
 The SQL query is SELECT * FROM TestMembers WHERE Username = 'Tom'
and since Tom happens to be a member of our website we get a success message.
 
correct log
 
2) An evil user familiar to SQL enters x'; DROP TABLE TestTable;--
The SQL query is  SELECT * FROM TestMembers WHERE Username = 'x'; DROP TABLE TestTable;--'
 
 
sql injection
 
Wow. A total table is deleted. The malicious user somehow found out that we have a table called TestTable and took great advantage of it. Instead of deleting the table he could as well have created new rows or updated existing rows ( passwords etc) and do many nasty things before we get a clue that something bad has happened.
 
This kind of attack is called SQL Injection.
 
3) Another evil user, this time familiar with JavaScript, enters "<script>alert("Gotcha!");</script>"
What does our label show?
Could not log In. Username <script>alert(\"Gotcha!\");</script>does not exist in the database.
 
However the actual result is
 
cross-site scripting attack
 
 
Boom. A total stranger inserted a script in the page he received. Well ok, that's no big deal since in our case he's the only person who can see this alert. However, what would have happened if the person had signed in using that script as a username? Supposing our website has an administration site, when the administrator visits the member's page the script will be executed as well. Then the administrator will get this alert as well. And if you think that a simple alert message is no big deal, keep in mind that using JavaScript the user can get much more valuable information and we may never get a clue of that.
 
This kind of attack is called Cross-Site Scripting Attack.
 
Keep in mind that by default, asp.net will throw an exception if you try to post a script message. This is a useful precaution set by the framework so that inexperienced developers will be protected by cross-site scripting attacks. And that's quite useful. For example it is quite uncommon that a person might  want to sign up using a script within his user name. However there may be times a user may want to include script in his input. For example forums that have to do with web development are quite common to include scripts in their posts. In that case we do not want the framework to block these messages. To do so, we set 
validateRequest="false" 
in our page properties. From now on it's up to us to avoid such attacks.
 

Watch out for the input.

It's not as easy to be protected from all kind of attacks. We will first discuss how to protect your site from attacks that have to do with input, like the examples above.
 
What happened, is that the user took advantage of the fact that there was no validation in the field we asked for data. So he easily filled our textbox with nasty code. And it's not all in what you insert in textboxes. Everything that comes to you from the web must validated. And I mean everything.
  1. Textboxes and all types of form input
  2. Query String
  3. Cookies
  4. Viewstate
 
These can be altered quite easily, so they all have to be validated.
 
A good way to start your validation is to see if the input contains what is supposed to contain. If the input contains money amount, check if you can cast it to double. If you get an exception, the input is no good. It's a good idea to handle such exceptions using try/ catch so you can have total control of the flow. And like we said, use an error page. Look at the following code.
 
//Amount validation part
double amount;
try
{
  amount = Convert.ToDouble(AmountTextBoxID.Text);
}
catch(FormatException ex)
{
  //If the conversion fails then we should show the error page
}
// Do whatever you wish with the amount value, since the input was no good
 
If you want, you can do extra validation using regular expressions, to check, for example, if an email input seems to have email format etc.
 
OK, this will do something, but how can we protect ourselves against input that is supposed to contain a string? A nice way to prevent simple cross side scripting attacks is to use the HtmlEncode method located within the System.Web namespace.
 
HtmlEncode should be used before inserting the input to the response. HtmlEncode will return the input string having replaced all html characters with html-encoded text. For example '<' will be turned to "&lt;" and '>' to "&gt;" This way the browser will treat them as simple text and no scripts will be executed.
 
Look what happens to the previous input when we use HtmlEncode.
Instead of 
Could not log In. Username <script>alert(\"Gotcha!\");</script>does not exist in the database.
We get
Could not log In. Username &lt;script&gt;alert(&quot;Gotcha!&quot;);&lt;/script&gt;does not exist in the database.
 
This will work just fine and fill the label with the actual input, protecting us from possible problems.
 

Preventing SQL Injections

Now, what to do with the SQL Injections? The solution to this problem is quite simple. We will use parameters in the SqlCommand object instead of creating a simple query string. For example
 
//Use SqlParameters in our command instead of creating a plain sql query
string sql = " SELECT * FROM TestMembers WHERE Username = @Username";
 
SqlCommand cmd = new SqlCommand(sql, con);
//Add parameters to the SqlCommand object
cmd.Parameters.Add(new SqlParameter("@Username", evilTextBoxMessage));
 
When a value is set to an SqlParameter then it is attached to the parameter. In other words, no matter what we write in the textbox, its content will always be used in order to filter the results based on the Username column.
 
Another way to cancel SQL Injection attacks would be to use stored procedures in about the same way. You can also use LINQ instead. No matter what we choose to do, what we need is to bind the value with the parameter so it will execute nothing more than it is supposed to.
 
This is the first method using the new, more secure methods we talked about.
 
 
 
protected void LogInButtonClicked(object sender, EventArgs e)
{
  //Get the text to enter in our sql query
  string evilTextBoxMessage = EvilTextBox.Text;
 
  string connectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
  SqlConnection con = new SqlConnection(connectionString);
  //Use SqlParameters in ouir command instead of creating a plain sql query
  string sql = " SELECT * FROM TestMembers WHERE Username = @Username";
 
  SqlCommand cmd = new SqlCommand(sql, con);
  //Add parameters to the SqlCommand object
  cmd.Parameters.Add(new SqlParameter("@Username", evilTextBoxMessage));
  try
  {
  con.Open();
  SqlDataReader reader = cmd.ExecuteReader();
  if (reader.HasRows)
    //Log the user
    ResultLabelID.Text = "Logged In. Welcome " + EvilTextBox.Text;
  else
    //Show failure message
    ResultLabelID.Text = "Could not log In. Username " + Server.HtmlEncode(EvilTextBox.Text) + "does not exist in the database.";
    reader.Close();
  }
  catch (Exception ex)
  {
  //Try/catch can be used both to check for connection problems and sql injection attacks
  }
finally
  {
  con.Close();
  }
 
 
  //Amount validation part
  double amount;
  try 
  {
    amount = Convert.ToDouble(AmountTextBoxID.Text);
  }
  catch(FormatException ex)
  {
    //If the conversion fails then we should show the error page
  }
  // Do whatever you wish with the amount value, since the input was no good
 
}
 
 

Identity Spoofing Attacks

We are doing well, but still our website isn't secure even against simple attacks. Identity Spoofing is the next thing we should take into account. A logged user usually has some kind of cookie that contains data for the server. This way he is logged automatically next time he visits - he doesn't have to log in using his credentials. Supposing the data stored in the cookie is the user ID, then the user can easily change it and log himself as another user. 
 
This is very very bad. That's why it is much better to create a hash of the data that is to be stored in a cookie.
 
Actually sensitive data, such as passwords is best to be stored as a one-way hash. When a user tries to log he is not authenticated based on his username and password but on his username and hash of password. Anyway, back to the cookies.
 
If you have a cookie with your user ID set to 26 in your browser, you can simply change it to 27 and it's highly possible you will be logged as another user. However if you have a hash, it's highly improbable that spoofing another user will be a piece of cake. 
 
It's also a good idea to encrypt your viewstate using the ViewStateEncryptionMode parameter if you store sensitive data within it.
 
 
identiy spoofing
 

Eavesdropping attacks.

A serious attacker can use certain tools to monitor the communication between your server and the clients. This is not good for you (or your clients). This way the attacker can get hold of everything, cookies, session ID (contained within the ASP.NET_SessionId cookie), and the viewstate. Let alone the get and post values. This way he can easily imitate the user he got all the info from. There's no easy trick to prevent this. You will have to use secure connections.
 
Web is a bad thing considering that everything is sent within it. As a result everything is exposed to attacks. Using secure connection, will minimize the ways an attacker can use against you, but still it won't be easy to close all doors.
 

Conclusion

We have made a trip through the methods an attacker can use against us and how to defend against them. SQL Injections can be blocked by using SqlParameters. Cross-site scripting attacks can be matched by checking the input's type and expected value. We have also seen how someone can imitate an existing user and how a secure connection can help us. 
 
 
 

Back to BlogPreviousNext

Comments


  • 14-07-2015, 10:56 AM
    Elcin
    Posts: 1
    I love the way you put the article toehtger. It’s clear you have put a lot of thought into this for our benefit and we truly appreciate it. It is not often that one read a quality post such as this one.

Leave a comment
Name: