Most discussions of software security concentrate on the applications themselves or the
data they contain. For example, a lot of time is spent talking about validating
POST variables that users submit before that information is sent to a database.
Similarly, there's been a lot of ink spilled on the various encryption systems
Most of the time, though, it pays to elevate your gaze a bit and think about security at the application architecture level. Why? Because at this level, it isn't the geekiest who survives; it's the person who thinks in terms of strategy, policy, and procedures. Suppose, for example, you have a contact form on your Web site. Users fill out the form and click Submit, which instructs the mail server to send an e-mail message to a designated e-mail account. At a tactical level, your developers may do all the smart things to secure this form. They may validate every form field entry to remove e-mail injection commands, embedded Hypertext Markup Language (HTML) tags, and other naughty bits. They may even filter requests by incoming IP addresses or set up a cookie to control access to the form.
However, at this point, the security measures stop. Any competent hackers can spoof their IP address every time they visit the form, so they can easily subvert that simple security check. What happens if a malicious user decides to submit the form 10,000 times in a single day? True to form, 10,000 requests hit your mail server, and it dutifully goes about its task. The problem is, mail servers can't tell the difference between a spurious request and a real request. While the mail server is bogged down with all the spurious requests, it can't handle real e-mails, some of which may be sales leads or support requests. One response to the problem is to mandate a Completely Automated Public Turing test to tell Computers and Humans Apart (CAPTCHA) device on each form to tell the difference between humans and computers.
Are some CAPTCHA devices better than others? Can some be subverted? Of course, but picking the right CAPTCHA device is an implementation detail. What you're worried about at the application architecture level is that you've covered the problem.
As you can tell from this very brief example, approaching security from the application architecture level requires strategic thinking. You can't just think of point defenses, you have to figure out weaknesses in the underlying system, weigh the threat against them (that is, the likelihood of attack), the consequences of doing nothing, and then the application of defensive systems.
Skills and competencies
What kinds of skills will you need in the role of security architect? You'll need to think abstractly, navigate politics, set up policies, and think like "the enemy," for starters. In short, you're going to have to acquire a whole new set of strategic tools.
Working at the application architecture level requires you to shift your thinking from the concrete work of coding, quality assurance, and hardware to more abstract levels. Instead of working directly with code or hardware, you're going to be thinking about systems and how they interact. You're going to need to know how enterprise systems as diverse as content management and enterprise resource planning (ERP) play together; you're also going to be working with outside vendors and their applications, such as sales force automation systems and other specialized databases.
Navigating politics and policies
Unfortunately, security architecture is all about politics. In an ideal world, all information technology (IT) assets would be free for use by anyone, anytime, anywhere. That's not our world, though, so you have to define who gets access to what and when/where/why/how. Doing so can require some difficult decisions, such as requiring that all applications work with single sign-on (SSO) to simplify access to commonly used reference materials. These rules are usually encoded in a security policy.
Good security architecture (and just plain security, period) begins with a good policy. Know what systems you have, what's on those systems, and which users need access to them. Make sure that everything is documented, because without documentation, you can't enforce anything. For example, you may decide at the policy level that users of your application can upload files but only if those files are images, Portable Document Format (PDF) files, and Microsoft® Word documents less than 500 KB in size. This kind of policy can be enforced at all levels in your system architecture and application business logic.
What does a good security policy even look like? It depends on your organization. It may be an informal document that's stored on the company intranet, or it may be a binder in the IT department. Whatever form it takes, it must be a living, breathing entity that's easy to update and easy to reference. Otherwise, no one will use it and no one will abide by it.
The other part of this equation can be loosely organized under the "how you react to pressure" category. At one point or another, you will experience a security breach or malicious attack of some kind. There will be something you never thought about. What kinds of systems and processes are in place to react to these situations? How you behave during stressful situations is just as important as planning for the problem in the first place.
Think like the enemy
Your role is security, and the only way to get your job done is to really get inside the "enemy"; that is, the person(s) trying to break your security. This mindset colors everything you do: It shows up in your security policies, in your security testing plans, in your quality assurance plans. If you know that there are 500 exploits for a certain type of key application in your application bundle, you have to be sure that someone tests all 500 before you go live (or at least all those that would cause catastrophic problems).
If you're building a typical Web application, you'll generally have a section called /admin or /admintool that houses all the administrative screens that allow actual control and manipulation of data. For example, with a content management system, you'll have sections and screens that allow users to create and update press releases, pages, binary documents, and other information assets. In other words, from a security perspective, the existence of such an area presents a big, fat, juicy target to anyone who wants to deface or damage the Web application. Common sense dictates that you do something about these targets, right?
The best thing to do in this case is remove the administrative interfaces from the server hosting the Web application. That's right: Create a secondary administrative server that houses this administrative capability. But that's not the only thing you should consider. Not only move the administrative screens to another server, but make sure that this server is accessible only on a private network. This, of course, requires that the administrative interface populate databases and file repositories properly from its remote location to the main Web application server.
If you can't move your administrative areas to another server, move them to a different port on the main server. For example, make the administrative screens available only on a high-numbered random TCP port (not 8080). You have 64,000 or so to play with, after all. Also, add Secure Sockets Layer (SSL) security to the entire login process, and store encrypted passwords for users so that they can't be eavesdropped on. Finally, don't resort to a common name like admin (I know, we've all done this at some point) for this part of the Web application. How about something like /manage or /sitecontrol?
The key thing to remember here is that you probably won't catch everything. After all, you'd have to be right every time, whereas, the hacker, with infinite patience to probe your defenses, only has to be right once. So, you must do two things: Think like the hacker, and invest in good processes that allow you to stay one step ahead.
Defense in depth
The idea behind defense in depth is simple: Never rely on just one security method. Don't just use a moat, use a moat and a wall. Then, add random patrols inside the walls to verify people's identity. Put locks on the doors and windows of each building. Chain a dog to the front door (preferably a big, loud, mean, barking dog). Have people check in with their neighbors every few hours to make sure things are okay.
As with anything else, defense in depth is a balance between security and utility. Too much security, and regular users are hampered. Too little security, and your only defense system will be thwarted and allow full access to everything inside that checkpoint.
What are some tangible examples of defense in depth? Well, when dealing with user input from forms, for example, you typically check each form submitted to make sure that it's what you expect (numbers, ZIP code, alphabetic characters, and so on). You can run this check along with a check for maximum size (to avoid buffer overload attacks) on the client side, but because anyone can thwart these measures, you also check on the server side. Not only that, but you can make sure that nobody is trying to add malicious HTML code, an uploadable file, or a Structured Query Language (SQL) injection.
After this round of cleansing, you make sure that you pass all data through
the equivalent of a database-safe function such as the
mysql_real_escape_string() so familiar to PHP
programmers. Why do that after you've already cleansed the data? Because you
never know when someone will be smarter and sneakier than you, that's why.
Can you take another step? Sure. If you're issuing some kind of
command, perhaps it would be wise to populate a temporary table and alert
administrators to approve the change before everything is finally committed.
If the data is issuing a
delete command on a
database row, make sure that you add
limit 1 to
the end of your statement to minimize damage. (And yes, you might also copy
the affected row to a backup table just in case!)
Tools and techniques
You may have been used to creating systems on the fly, but now your role is to explain to others what you want. To do that, you'll need to pick up some new tools for your toolbox, like the Unified Modeling Language (UML).
UML and personae
If you've been working in computer security for any amount of time, you're used to the following types of questions surrounding any application:
- Are there parts of your application, such as administrative interfaces, that require users to log in? If so, how are you handling authentication?
- Can users register to create their own user names, or are the names based on users' e-mail addresses or some other potentially well-known construct (first letter of first name plus last name)?
- Are passwords randomly selected by the system, or can users select
their own? If the latter, does the system check for common weak passwords such as:
- Passwords that are less than seven characters in length?
- Passwords that are the same as the user name or the user name reversed?
- Passwords that don't have a mix of lowercase and uppercase letters, numerals, and special characters?
- Passwords that are common dictionary terms or names of characters from books and movies?
These are all good questions to consider, and none of them should be ignored in favor of "higher-level thinking." However, at the application architecture level, you have to step up to another level. You have to think first about your users, their roles, and what they get access to because of their roles.
The best tool I've found for this kind of discussion is the persona. For example, if I'm designing an enterprise content management system for a client, I always try to figure out who the users are and what they need to accomplish. For each user, I build a persona, like this:
- Tina, the marketing manager. Tina is a 15-year veteran of the high-tech marketing world. Five marketing specialists work for her. Tina must be able to approve all content published on the site, but she does no initial creation of content herself. She can see all the content on the Web site.
- Tom, the public relations (PR) writer. Tom can only create and edit press releases and news items. He has no authority to publish content, nor can he delete anything from the live site.
- Jill, the marketing project manager. Jill is in charge of two sections of the Web site: products and solutions. She can create new content and refresh content that is already published, but she must have final approval for new content to go live.
- Tony, the events manager. Tony is in charge of the events calendar and contact forms on the site. He can publish directly to the events calendar without approval.
- Ruth, the copywriter. Ruth is in charge of writing copy for any part of the Web site, and she is usually tasked with different assignments every day for making improvements on the site. She can create content from scratch and edit existing content, but she can't publish anything without sending it through Bill first.
- Bill, the editor. Bill typically checks everything before it's sent to Tina for final publication approval.
Notice that these personae are completely nontechnical. All you're doing here
is talking nouns and verbs. You identify each role and what that role can do
with the different types of data. Later, you can make a more detailed pass and
talk about database-type actions they can take (for example, Tina can run
select(*) on the Page, Pr, and Images tables).
But how do you decide who gets access to what? Follow the principle of least privilege. Give users the minimum amount of access to functions and modules that allow them to do their jobs, and take away that privilege at the earliest convenient time. If you have to give them additional privileges, compartmentalize that extra boost to their security profile, then take that privilege away as soon as they're done working.
Trust, but verify with logging
Just because you've designed a system with Tina the marketing manager in mind doesn't mean that Tina will always do what she's supposed to or that she won't pick a bad password that's easy to figure out. Log everything every user does, from the moment the user logs in to the moment he or she logs out. Log it to a flat file, database, off-site tape backup, whatever -- but log it.
Why all the logging? Because you want to be able to reconstruct what happened later. You want to see the trail that the user followed, from initial login to every action performed on the system. This doesn't just make sense from a forensics point of view; it also allows you to learn how users work with the system. You might discover, for example, that everyone bounces around a lot inside your application. Perhaps a better search engine or better cross-linking might smooth things out.
Security for data while in transit or in storage is a very important part of the discussion. In your previous role as developer, you'd normally begin the entire discussion with encryption methods, SSL certificates, and the like. At the application architecture level, again, you want to think of nouns and verbs.
For example, if you're storing data, where is it being stored? As flat files, or in a database? Above the Web server root, in the Web server root, on a dedicated media or file server, or a shared mount point? The answer to these questions, of course, is really all about the users who need access to the data and how they normally access it. If they need to retrieve the data by performing detailed searches, some kind of database would be smart. The same is true if they need fast retrieval of the data.
Now that you've thought a bit about who needs access to data and how they retrieve it, you can think about security. One of my favorite things to do is put downloadable binary files above the Web server root, then provide access to them only through a fetching program. The fetching program can be left bare, or it can require some kind of user login, cookie, or session variable before it retrieves the file. You can attach a simple logging system at the end of the process that keeps track of each download of the item in question. Very simple to implement, but it has to be thought out well in advance to make it work.
Security for data communication is another important aspect to consider. Again, think big. First ask yourself, where does our application communicate with itself and with other systems? Can we secure all these points? Is it worth it to do so? For example, any part of your application that deals with e-commerce, banking, or finances requires the heaviest data security and encryption you can get your hands on. Any time you deal with sensitive customer or user information (ranging from birthdays to private medical information), don't use plain-text messages if you can help it. Many application platforms allow the use of public key cryptography to encrypt, send, and decrypt messages with relative ease. If you can't see your organization adding this kind of overhead to its messaging, only send minimal information in your messages, and require the recipient to log in somewhere to see the rest of the data.
Consider the following skill and competency milestones for any application architecture security effort:
- Application security policy. The expectation here is to develop a document that sets down the rules for various parts of your application. How will data be used and accessed? Which rules will be followed on the network? How does your application play with other applications and systems? How does your application fit into the overall enterprise security policy? From a policy-maintenance standpoint, you must also figure out what form your policy document will take, who has input to that document, and who maintains it going forward.
- Define personae and workflows. After you've got a security policy, define personae and workflows. You have to know how and where applications interact with security apparatus. For example, if you know that certain users have similar access requirements, you might consider adding a grouping concept to your application to make user management easier. You might also reconsider your privilege model if you know that a certain subclass of users has increased responsibility over a certain part of the application. You won't know any of this if you don't map things out first.
- Define the security scope. At some point, you'll need to apply all this hard work to your application's architecture. Because this is probably being defined by a large team of contributors, you'll need to figure out a way to add your scope to the overall picture. (Remember the discussion about politics?) Too many times, security is given a lot of lip service, then added at the end. Get your team to resist this urge by incorporating what you know about the system and its users early on.
Working at the application architecture level means stepping up to a whole new way of thinking. You have to be more strategic, think more abstractly, and use communication tools and technologies (such as UML) to universally describe what you want from your team. You must also think at a much higher level about security than simply tactical touchpoints. With any luck, this article has started you on your path.
- Learn more about security architecture in "Career management 101 for information security pros" (SearchSecurity.com, June 2006).
- Read "Application Security: Threats and Architecture" (PDF).
- Read "Improving Web Application Security: Threats and Countermeasures" at MSDN.
- Architecture area on developerWorks, get the resources you need to advance your skills in the architecture arena.
- Browse the technology bookstore for books on these and other technical topics.
- Check out IBM on demand demos to learn about various software products and technologies from IBM.
- Stay current with developerWorks technical events and webcasts.
Get products and technologies
- Download IBM product evaluation versions and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
- Participate in the discussion forum.
- Check out developerWorks blogs and get involved in the developerWorks community.
- Participate in the developerWorks Architecture discussion forum.