Jeff Atwood, a prominent voice in the .NET community, had an interesting post over on Coding Horror the other day regarding code maintenance. In it, he references the C2 Wiki Page in saying Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live. I think this should be taken a step further and cover security. I would suggest - Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live , and imagine that the maintainer is also your corporate Information Security Auditor/Pen Tester/Application Security Expert.
Don't get me wrong, in no way am I advocating that the security problems of today's applications lay solely the shoulders of developers. On the other, hand I believe that a large part of the problem is education and awareness training, or the lack thereof. If corporations want to secure there applications they must educate their developers on what is possible in today's world and provide them with concrete patterns and methods of combating and preventing such attacks. Until all companies accept this philosophy, the above referenced individuals will continue to scream during code reviews and application assessments. They will also continue to have nightmares of their pager to going off and hearing the words "We've been hacked! What do we do now?!" Hopefully you will never have to experience such a situation, but that is no excuse for not being aware that it could happen.
Just remember, an attacker does not care what you designed your application to do. They are only concerned with what it is capable of doing. In that regard, your application does not only need to function properly, but it needs to function securely to be truly effective at protecting your data. Security, after all, is a feature and should be given just as much design and implementation review as any other part of the application.
Coding For Violent Psychopaths
Posted by
Matt Presson
on Sunday, June 22, 2008
/
Labels:
Access Control,
Audit Logging,
Data Protection,
Input Validation,
Secure Infrastructure
/
Comments: (0)
Design vs. Test - Where security comes into play
After talking about security design to numerous development teams one thing has continually stood out as a prevailing question: Where in the SDLC do we start to look at security?
The simplest answer, and the one I always provide, is "as early as possible". In most cases this will be the design/concept phase when everything is kind of in flux and requirements - business NOT system - are still being thought through.
It is absolutely imperative that security be incorporated into the design as soon as possible. One compelling reason it that if it is mixed into the design developers have a harder time trying to get out of it later. Secondly, you can figure the required time into the development efforts instead of adding it at the last minute and expecting the budget and milestones not to change. Lastly, when security is considered early, the code just seems to come out with less vulnerabilities.
In any case, it is just better to design security in than to attempt to retrofit it into the application.
The simplest answer, and the one I always provide, is "as early as possible". In most cases this will be the design/concept phase when everything is kind of in flux and requirements - business NOT system - are still being thought through.
It is absolutely imperative that security be incorporated into the design as soon as possible. One compelling reason it that if it is mixed into the design developers have a harder time trying to get out of it later. Secondly, you can figure the required time into the development efforts instead of adding it at the last minute and expecting the budget and milestones not to change. Lastly, when security is considered early, the code just seems to come out with less vulnerabilities.
In any case, it is just better to design security in than to attempt to retrofit it into the application.
Aircraft engineering vs. Software engineering
Today I was able to participate in the 10th Annual AT&T Cyber Security Conference. The agenda for the conference can be viewed here. Regardless of how you may feel about AT&T the company, the web cast was quite informative and had quite a wide range of topics and speakers. One of the presentations that stood out in my mind was given by Dr. Edward Amoroso, AT&T Sr. VP and CSO. The reason that this particular presentation stood out is that he made an interesting comparison near the end of his presentation that I find inherently flawed. The question he proposed was when will software engineering have the same amount of structured processes and ensured quality as aircraft engineering?
In the first place I would never compare the two and I know few people that would. On the one hand, aircraft engineers have a huge responsibility in that if their product fails hundreds of people at a time could potentially loose their lives. I know of few systems, other than aircraft software, with such impacts. Secondly, aircraft engineers are given copious amounts of time to develop their product and "get it right". Software developers are generally told to get the product out as fast as possible and if it passes the functional tests it is considered finished and good to go. If aircraft engineers were given the same leeway, many more planes would be falling out of the sky.
Now to look at it from a security perspective, one of the leading causes of poorly implemented security controls, and flawed software in general, is a lack of sufficient design and development time. Secure software simply takes longer to write. It is a fact. Such software almost always has a larger code base as a similarly functional product with less security. This is only logical and should not be of any surprise to anyone as the implemented security controls require code. Subsequently, a software product with more security should take longer to write. Now I am not advocating the more security means more secure. Do not take the above statements in the wrong manner. I simply mean to say that software that has the appropriate security controls in place to protect the application and its data will have more code.
To address the quality issue, this has to be addressed at a managerial level. Management must come to the realization that quality software tests more than just functionality. An application, web or otherwise, needs to be evaluated for more than what it is designed to do. It needs to be tested for what it can do. Test for not only what developers designed it to do, but what can an attacker make it do that it was never designed to do. All of this testing does add additional time to the development schedule, but it is necessary time to ensure quality software.
So to answer Dr. Amoroso's question, software engineering will never have the same amount of structured process and quality assurance as aircraft engineering unless time is given to the developers and testers and emphasis is placed upon more than just functional testing. As long as software has to be developed today and deployed yesterday, flawed software will continue to be pushed out the door.
In the first place I would never compare the two and I know few people that would. On the one hand, aircraft engineers have a huge responsibility in that if their product fails hundreds of people at a time could potentially loose their lives. I know of few systems, other than aircraft software, with such impacts. Secondly, aircraft engineers are given copious amounts of time to develop their product and "get it right". Software developers are generally told to get the product out as fast as possible and if it passes the functional tests it is considered finished and good to go. If aircraft engineers were given the same leeway, many more planes would be falling out of the sky.
Now to look at it from a security perspective, one of the leading causes of poorly implemented security controls, and flawed software in general, is a lack of sufficient design and development time. Secure software simply takes longer to write. It is a fact. Such software almost always has a larger code base as a similarly functional product with less security. This is only logical and should not be of any surprise to anyone as the implemented security controls require code. Subsequently, a software product with more security should take longer to write. Now I am not advocating the more security means more secure. Do not take the above statements in the wrong manner. I simply mean to say that software that has the appropriate security controls in place to protect the application and its data will have more code.
To address the quality issue, this has to be addressed at a managerial level. Management must come to the realization that quality software tests more than just functionality. An application, web or otherwise, needs to be evaluated for more than what it is designed to do. It needs to be tested for what it can do. Test for not only what developers designed it to do, but what can an attacker make it do that it was never designed to do. All of this testing does add additional time to the development schedule, but it is necessary time to ensure quality software.
So to answer Dr. Amoroso's question, software engineering will never have the same amount of structured process and quality assurance as aircraft engineering unless time is given to the developers and testers and emphasis is placed upon more than just functional testing. As long as software has to be developed today and deployed yesterday, flawed software will continue to be pushed out the door.
Session fixation, a problem easily overlooked
Session fixation is a problem that web applications can have but not realize until it is too late. In general, session fixation derives directly from flaws present within the login mechanism, namely failure to generate a new session for a user upon successful authentication. This vulnerability, when exploited gives attackers the ability to directly influence a user's session id and therefore assume the identity of a targeted user within the system.
At the heart of session fixation generally lies code similar in function to the following:
So, how do you protect your application from these types of attacks? Look at the following updated version of the Login servlet.
What this means is that the id being used to reference the session used during login no longer points to a valid session object on the server. As such, that session token is no longer valid and cannot be used for anything effectively preventing an attacker from logging in as the targeted user. Now, as long as there are no XSS vulnerabilities that could allow the attacker to use
Although the actual application code required to prevent session fixation is trivial in nature, it is very important that such be put in place. Otherwise, targeted attacks against your user base could result in large compromises of your application and therefore your data.
At the heart of session fixation generally lies code similar in function to the following:
login.jsp:
< %@ page session="true" % >
< html >
< head >
< title >Login< / title >
< meta http-equiv="Content-Type" content="text/html; charset=utf-8" / >
< meta name="robots" content="noindex, nofollow" / >
< meta http-equiv="pragma" content="no-cache"/ >
< meta http-equiv="cache-control" content="no-cache"/ >
< / head >
< body bgcolor="#66CCFF" onload="document.loginForm.username.focus()" >
< table width="500" border="0" cellspacing="0" cellpadding="0" >
< tr >
< td >
< form name="loginForm" method="post" action="Login" >
< table width="500" border="0" cellspacing="0" cellpadding="0" >
< tr >
< td width="401" >< div align="right" >User Name: < /div >< /td >
< td width="399" >< input type="text" name="username" / >< /td >
< /tr >
< tr >
< td width="401" >< div align="right" >Password: < /div >< /td >
< td width="399" >< input type="password" name="password" / >< /td >
< /tr >
< tr >
< td width="401" > < /td >
< td width="399" >
< br / >< input type="submit" name="Submit" / >
< /td >
< /tr >
< /table >
< /form >
< /td >
< /tr >
< /table >
< / body >
< / html >
Login Servlet:
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
public class Login extends HttpServlet {
private final int MAX_LOGIN_ATTEMPTS = 5;
private boolean canFindUser(String username, String password) {
// Do LDAP, AD, Database lookup functionality here
// and return appropriately
}
private void lockAccount(String username) {
// Do account locking here
}
public void init(ServletConfig config)
throws ServletException {
super.init(config);
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Get context info
ServletContext context = getServletContext();
RequestDispatcher dispatcher;
// Get the user's session created on the login.jsp page
// Do not create a new one
HttpSession session = request.getSession();
// Get request parameters
String username = request.getParameter("username");
String password = request.getParameter("password");
// Check maximum logins attempts
int loginAttempts = (session.getValue("loginAttempts") == null) ? 1 : session.getValue("loginAttempts");
if (loginAttempts > MAX_LOGIN_ATTEMPTS) {
lockAccount(username);
dispatcher = context.getRequestDispatcher("/accountLocked.jsp");
dispatcher.forward(request, response);
}
// Find the user
if (canFindUser(username, password)) {
session.putValue("User", new User(username, password));
dispatcher = context.getRequestDispatcher("/index.jsp");
}
else {
session.putValue("loginAttempts", loginAttempts + 1);
dispatcher = context.getRequestDispatcher("/login.jsp");
}
dispatcher.forward(request, response);
}
public void destroy() {
// do nothing
}
}
As mentioned earlier, session fixation revolves around failure to provide a new session token to a user once they are authenticated (a trusted user state). Instead many applications use the session token utilized during the login process prior to the user being authenticated (an untrusted user state). The key message to pick up at this point is that prior to a user authenticating, your application must assume that the session token being passed to it was generated in that user's browser when they first accessed the login page. This is a very bad assumption to make as it is trivial for an attacker to create and distribute links including a session token that they know and get users to click on the them. This can be accomplished in many ways, the simplest of which only involve adding a JSESSIONID, PHPSESSIONID or ASPSESSID parameter to the URL. As you can see this attack, like many others, is implementation language agnostic. Once the targeted user is logged in, the only step the attacker needs to take is to refresh his/her browser. Given that the session token has not changed during the login process, the attacker has justed assumed the identity of that application user without having to know any credentials. As administrative accounts are usually the most prized in any application, this attack is used quite frequently in spear phishing attacks targeted towards site administrators.So, how do you protect your application from these types of attacks? Look at the following updated version of the Login servlet.
Login Servlet:
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
public class Login extends HttpServlet {
private final int MAX_LOGIN_ATTEMPTS = 5;
private boolean canFindUser(String username, String password) {
// Do LDAP, AD, Database lookup functionality here
// and return appropriately
}
private void lockAccount(String username) {
// Do account locking here
}
public void init(ServletConfig config)
throws ServletException {
super.init(config);
}
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Get context info
ServletContext context = getServletContext();
RequestDispatcher dispatcher;
// Get the user's session created on the login.jsp page
// Do not create a new one
HttpSession session = request.getSession();
// Get request parameters
String username = request.getParameter("username");
String password = request.getParameter("password");
// Check maximum logins attempts
int loginAttempts = (session.getValue("loginAttempts") == null) ? 1 : session.getValue("loginAttempts");
if (loginAttempts > MAX_LOGIN_ATTEMPTS) {
lockAccount(username);
dispatcher = context.getRequestDispatcher("/accountLocked.jsp");
dispatcher.forward(request, response);
}
// Find the user
if (canFindUser(username, password)) {
// Killl the current session created by the jsp so it can no longer be used
session.invalidate();
// Create an entirely new session for the logged in user
HttpSession newSession = request.getSession(true);
newSession .putValue("User", new User(username, password));
dispatcher = context.getRequestDispatcher("/index.jsp");
}
else {
session.putValue("loginAttempts", loginAttempts + 1);
dispatcher = context.getRequestDispatcher("/login.jsp");
}
dispatcher.forward(request, response);
}
public void destroy() {
// do nothing
}
}The difference that you should notice in this updated code is that upon successfully finding the user, the current session is terminated and rendered useless by a call to session.invalidate(). From the Java documentation here, the function "[i]nvalidates this session and unbinds any objects bound to it." What this means is that the id being used to reference the session used during login no longer points to a valid session object on the server. As such, that session token is no longer valid and cannot be used for anything effectively preventing an attacker from logging in as the targeted user. Now, as long as there are no XSS vulnerabilities that could allow the attacker to use
document.cookie to steal the login session that way, your application has now successfully reduced its attack surface which is always a good thing.Although the actual application code required to prevent session fixation is trivial in nature, it is very important that such be put in place. Otherwise, targeted attacks against your user base could result in large compromises of your application and therefore your data.
The most important thing in application security
What is the most important thing in application security? To ask it a different way: What is the single thing that an application must get right in order to protect its data, and by extension its users, from being compromised? After talking with several people that I frequently discuss such things with, it became apparent that it has to be access control. In my opinion, access control is the cornerstone of application security. Without it, all of your data may as well be publicly accessible. When done right, your data will stay where it should be, in your hands under tight control with access to it only by those who have been explicitly granted access.
So, how are developers supposed to implement such a tight access control component? The answer is a surprisingly simple combination of controls: 1) Validate all input for correct format, rationality, and business rule adherence 2)Encode all output in a context aware manner as to prevent corruption/compromise of the system and its users and 3) Perform authorization at every access point in the application.
Although these three guidelines appear simple at first glance, getting them right can be quite difficult depending on the complexity of the application being developed. Additionally, you may notice that the access control guidelines cover more than just ACLs and calls to isAuthorized() and isInRole(). This is for good reason. Access control is so much more than this. Access control is about protecting every piece of data that an application stores, manipulates, and processes. For example, who should be authorized to see the value of a user's session token? Who should be able to see the values set in a user's cookies? By many people's definition of access control, these data elements are not considered even though, in my opinion, they are just as sensitive as any other piece of data in the system. In the case of the session token, this value allows any user to effectively become another logged in user at will. As far as cookie values are concerned, they can hold very sensitive information, although that is highly discouraged for various reasons. As such, these data elements require just as much protection as the data elements you store in your database that you protect from SQL Injection. If you don't know how to protect against SQL Injection, click here to find out how to solve this problem.
Proper input validation, output encoding, and stringent authorization are the keys to getting access control right. At the the heart of the matter, access control is nothing more than keeping what should only be accessed by specific individuals safe from being accessed by others. It does not only apply to the data you process, but it also applies to the data you generate and send back to the user.
So, how are developers supposed to implement such a tight access control component? The answer is a surprisingly simple combination of controls: 1) Validate all input for correct format, rationality, and business rule adherence 2)Encode all output in a context aware manner as to prevent corruption/compromise of the system and its users and 3) Perform authorization at every access point in the application.
Although these three guidelines appear simple at first glance, getting them right can be quite difficult depending on the complexity of the application being developed. Additionally, you may notice that the access control guidelines cover more than just ACLs and calls to isAuthorized() and isInRole(). This is for good reason. Access control is so much more than this. Access control is about protecting every piece of data that an application stores, manipulates, and processes. For example, who should be authorized to see the value of a user's session token? Who should be able to see the values set in a user's cookies? By many people's definition of access control, these data elements are not considered even though, in my opinion, they are just as sensitive as any other piece of data in the system. In the case of the session token, this value allows any user to effectively become another logged in user at will. As far as cookie values are concerned, they can hold very sensitive information, although that is highly discouraged for various reasons. As such, these data elements require just as much protection as the data elements you store in your database that you protect from SQL Injection. If you don't know how to protect against SQL Injection, click here to find out how to solve this problem.
Proper input validation, output encoding, and stringent authorization are the keys to getting access control right. At the the heart of the matter, access control is nothing more than keeping what should only be accessed by specific individuals safe from being accessed by others. It does not only apply to the data you process, but it also applies to the data you generate and send back to the user.