Never Ending Security

It starts all here

Web Security Coding Tips

Web Security Coding Tips

“Because all the firewalls in the world can’t protect you from yourself.”

  1. Never pass user-entered text as shell parameters!

    • This usually affects CGI or “gateway” programs that execute existing programs.
    • Users can pass additional commands separated by command separators (e.g. the semicolon.)
    • Assume a simple program that executes the command:
      finger [username]
      Think about: What would happen if somebody passed in the username:
      eliasen; rm -rf /
      on a UNIX system? Note that nasty semicolon! Ouch!
    • Make sure that your Web server executes all programs as a user with very few permissions.
    • Perl has a -T option to “taint” variables and prohibit execution of any user-entered information as command-line parameters. Use it in all CGI scripts.
  2. Don’t do “dumb” reads of input into memory. Limit number of characters you read into buffers.

    • C/C++ programs are especially susceptible to this type of problem. For example, if you have a fixed-length buffer, make sure you use forms of functions such as read() or strcpy() that only read up to a maximum number of characters.
    • This “overflow bug” can be used to crash your server or worse.
    • The majority of the attacks on Microsoft Web servers, including the Code Red worm, have exploited this category of bug. A simple sweep of source code could have found these problems at any time in the past several years, before it became a problem for tens of thousands of companies.
    • This type of bug in a version of “finger” was exploited by the famous Internet Worm. This allowed arbitrary code to be executed with root permissions.
  3. Don’t assume the user has used the front-end to your pages.

    • Browsers don’t send information about referring documents. (At least most don’t any more for privacy reasons.) You don’t know if they used your front-end or are submitting completely invalid information.
    • Users have all your HTML source and know every parameter you’re passing to your form-processing program.
    • Any page can be faked–users can save the HTML source and modify it at will.
    • Users can bookmark pages and jump to them in any order. Make sure every page checks that the user has logged in properly!
    • Don’t assume that pages were accessed in the expected order.
    • Using the HTTP POST method is no more secure than GET. GET is mindlessly trivial to exploit, though.
    • Using “hidden” form fields <INPUT TYPE="HIDDEN" ...> to pass information is neither hidden nor in any way secure.
    • Homework: Take an interesting page, save its HTML source to your hard drive, edit it a bit and see what happens when you pass unexpected parameters. Look especially for “hidden” form fields and experiment with those.
    • Even better than hand-modifying the HTML would be to use a tool like the Webdeveloper plugin for Firefox/Mozilla/SeaMonkey which allows you to trivially do things to break a site like convert POST forms to GET, to change SELECT fields to text inputs, make hidden form fields visible and editable, make form fields editable, allow unchecked RADIO buttons, remove maximum lengths from form fields, edit, modify, and delete cookies, and more, all at the click of a button. This plugin is astoundingly useful.
  4. Validate all information passed in again and again.

    • Make sure numeric messages are purely numeric.
    • Filter data very carefully for length, allowed characters, etc.
    • Structure your data so that it can be readily verified.
    • Even if your web front-end has a fixed number of options a user can select from, someone can easily edit the HTML and submit different information. Validate that all input parameters are within an expected domain of values.
  5. Never assume the client has used any client-side validation.

    • JavaScript can be turned off easily.
    • Submissions can be made without a browser–HTTP is very simple.
    • Don’t include validation rules in client-side JavaScript that give away too much information about what you’re trying to protect!
    • You should validate data both on the client and the server. This is the cost of having an application that is both secure and friendly and responsive to the user.
    • Usability tip: Never require that the client use JavaScript to use your pages. JavaScript should only be used to enhance interactivity.
  6. Don’t let users hijack your site–replace all potentially troublesome HTML characters before displaying them in HTML pages.

    • Replace at a minimum the following characters with their corresponding HTML character references: (see the source for this page to see how careful you have to be!) Write this utility before writing any HTML and use it consistently.
      • < -> &lt;
      • > -> &gt;
      • & -> &amp;
      • " -> &quot;
    • Users can submit HTML which inserts images into a page.
    • Think about: What if your web page allows someone to enter that their name is <IMG SRC=""> and you display that to other users?
    • Users entering JavaScript is especially dangerous–it can redirect anyone who tries to access your page to other sites:
      <SCRIPT LANGUAGE="JavaScript">window.document.location.href = ""</SCRIPT>
    • JavaScript is generally secure but can be used to do millions of annoying things like open countless windows ( ), shut down the browser ( window.close() ), or run the user’s machine out of memory and crash it.
    • Text extracted from databases, files, or other sources should be replaced similarly just to keep your site from breaking due to unexpected input. (What if the database contains text like “if a<b” and you display this in a web page? (I forgot to use &lt; when writing this example and half of the page didn’t display!))
    • If you don’t find yourself doing these replacements all over the place, you’re probably at risk.
  7. SQL is dangerous–never pass in unchecked text as an SQL statement!

    • Replace single quotes especially! The portable way is to replace single quotes with two single quotes: 'Alan's' becomes 'Alan''s'. Write a routine to do this before you write any SQL, and use it everywhere you use SQL. Remarkably, most database interface environments don’t have routines to do this and most books on connecting to databases slyly ignore the issue! (I’ll bet people named O’Brien can’t use half of the web apps out there!)
    • Some SQL engines, such as MySQL, break when passed the NUL character (ASCII 0). Detect and disallow odd characters such as these.
    • Environments that allow you to prepare statements and bind replaceable parameters at execute time can often be safer than building a dynamic SQL string and executing it. An example from Perl:$bodyStatement = $dbh->prepare("INSERT INTO tblSSAContent (SSAID, Content) VALUES (?, ?)");
      $bodyStatement->bind_param(1, $SSAID);
      $bodyStatement->bind_param(2, $html, {TYPE => SQL_LONGVARCHAR});

      In this case, you don’t have to worry about escaping characters–the database interface does this for you.

    • Verify that numeric parameters are purely numeric. The following SQL/Perl snippet selects a given employee from the database:
      "SELECT * FROM Employees WHERE EmployeeID=$empID"
      Think about: What if the string $empID contains:

      • 12 OR 1=1
      • EmployeeID
      • 1; DROP Employees
    • Verify that string parameters don’t contain quotes. The following SQL/Perl snippet selects a given employee from the database:
      "SELECT * FROM Employees WHERE LastName='$last'"
      Think about: What if the string $last contains:

      • ' (a single quote)
      • whatever' OR 'A'='A
      • whatever'; DROP Employees; SELECT * FROM Dual WHERE 'duh'='duh
    • Think about: What would happen if the above statements were UPDATE or DELETE statements? May God have mercy on your soul.
    • Always make sure that the database user account that your Web application uses to access the database has no more permissions than necessary. If it’s a read-only page, make sure it’s using an account with read-only privileges. If it only needs to update, make sure it doesn’t have delete privileges.
    • Homework: Break or break into half of the database-driven websites in the world using just the sort of attacks outlined in this section.
    • Again, the portable way to escape a single quote in SQL is with two single quotes, not with backslashes as the addslashes function ormagic_quotes mechanisms in PHP would have you believe. Those are generally not portable to databases other than MySQL. Don’t use them. Write your own, correct versions. You should be escaping characters differently if you’re inserting into a database than you should be escaping them if you’re displaying them in HTML. Write two functions and decide which is the proper one to use in each case. Definitely don’tever use magic quotes in PHP, as they alter all input before you get it in ways that are not unambiguously recoverable, and are often wholly undesirable, especially if you’re not inserting it into a database at all, (say, just displaying it on the screen, or using it to perform some logic,) and code that relies on magic quotes will break when you decide to put it on a server without this dangerous feature enabled. Make sure magic quotes are turned off before you write and test your first line of code.
  8. Don’t expose your source code.

    • You’re safe releasing your source only if your page has absolutely no exploitable security holes. It’s much easier to find security holes if you have the source.
    • Conversely, mature, public-source Web servers (like the Apache web server) can actually be much safer than the “latest and greatest” offering by a company that keeps its source to itself. See point 2 above.
    • Older versions of Microsoft’s Internet Information Server and Personal Web Server will return the source of executable scripts instead of executing them if you just follow the filename with a period. (Try this on any page ending with .asp) This was patched, but adding ::$DATAto the end of the URL is another variation that lets you access the source. This bug exists on NT and Windows 2000 systems that use the NTFS filesystem. A patch was released for this further hole but some servers remain vulnerable.
    • Some Java Servlet environments (notably SilverStream) can return the .class files for compiled servlets, which is trivial to decompile to source which can be examined for security holes.
    • Make sure all directories containing executable programs have read access and directory browsing turned off.
    • Many text editors may leave backup files with extensions like .bak or a trailing tilde. If a directory will both execute scripts (say, with a.cgi extension) and serve static documents, someone can try to view the backup file to see your code. This is a very good reason to configure your web server so that executables are never stored in the same directory as static content. A less secure solution is to ensure that your web server only serves files with certain extensions. Least secure is to routinely sweep for these files and delete them.
  9. Don’t expose structure of your SQL.

    • Some environments or programs will display SQL statements on failure. This makes holes very easy to exploit. See point 7 above.
  10. Don’t expose your error messages.

    • Most web environments will send out “helpful debugging information” if something’s wrong in your page, which gives users insight into how your code works.
    • In Java Servlets, catch all exceptions. Many servlet environments display stack traces to the user when an uncaught exception occurs.
    • In Active Server Pages, use On Error Resume Next and check the Err object and all errors returned from database accesses.
    • In all servers, turn off detailed error information in production environments.
  11. Send e-mail messages for all unexpected conditions to your developers.

    • Most errors don’t get logged anywhere, and only your frustrated customers see them and never report them–they just stop visiting your site! Notifying developers of unexpected errors with helpful details will help improve the quality of your site.
    • This lets you detect potential break-ins while they’re happening.
    • A unified e-mail notification scheme should be one of the first things you build into a web framework. Use it liberally and consistently, and provide meaningful debug information to your developers, not your customers.
    • Identify each error type with a unique identifier so you can make sure that each type of error only sends one e-mail (so as not to flood your developers or break down your e-mail system,) but log each occurrence of the error to a log file with appropriate information so you can debug later.
    • Write automated tools to detect problems in your HTTP log files. Look for HTTP error codes and accesses to “privileged” pages. Perl is great for this.
  12. Disallow directory browsing and understand which files your web server will make accessible.

    • “Test” files and administrative programs often creep into an application that you’d never want users to see.
    • Make sure secure files, data files, or anything that’s not a public HTML page aren’t stored in a directory that your server will serve.
    • Realize that if you open one directory to be served by a web server, all directories below that are usually also served.
    • Disallowing directory browsing is not enough–if users know the location of a file or if they can guess or brute-force attack your server, they’ll get it.
    • Recent stealing of credit-card information on several major sites was made possible by leaving the files that store credit card information in directories that were served by the web server. By knowing the “usual” name for these files, someone can request them from the web server and have them with minimal effort.
  13. Basic password authentication isn’t secure.

    • Basic HTTP password authentication transmits passwords unencrypted. (Username and password information is only BASE-64 encoded, which is no encryption at all–it’s just a way of keeping nonprintable characters from confusing applications.)
    • Don’t use UNIX or NT passwords for your Web application; packet sniffers can pick these up easily and then more than your Web application is compromised.
    • Most Web environments don’t do anything to prevent “brute force” password attacks. Someone can write a program to try thousands of passwords per minute, and the web server won’t “slow down” or disable the account like a typical login environment would.
    • Think about how to prevent brute-force attacks on your application. Use application-level security (i.e. write your own login routines and don’t trust the web server’s login routines.) Disable accounts after a certain number of login failures. Detect multiple simultaneous logins from different IP addresses to detect compromised passwords.
    • Give each user their own username and password that you can deactivate, and don’t use a “shared” account name and password. (This is obvious, but many web servers make creating a new username and password a hard thing to do, which is why many web applications have shared accounts. This is another argument in favor of building security into your application.)
  14. Turn off web server features you’re not using.

    • Many services are exploitable if not configured correctly, or even if they are. For example, the Code Red Worm exploits services in Microsoft’s Internet Information Server that most Web administrators don’t even realize they’re running, but are enabled by default.
    • Examine the list of directories served by your web server and remove all test programs, samples, and administrative applications.
    • Web server surveys like the one run by NetCraft can be used to find sites that are running web servers with known problems.
    • Web search engines can be used to find programs with known security holes.
    • Corollary: Even if someone doesn’t have anything against you, they can find you and attack you just because you’re using the wrong program or web server. The Code Red worm proved this amply–it randomly attacked any Microsoft web server that it could find.
    • The web servers that I run receive hundreds of attacks every day, and everyone loves me. This even applies to my valueless home web server with a randomly-changing IP address.
  15. Know what’s happening behind the scenes!

    • Learn HTML and carefully evaluate anything produced by your IDE!
    • Write consistent and valid HTML. A different browser can break your site when it interprets invalid HTML differently than your browser does. Just because a page happens to work in your browser is no reason that it ever should work. And there’s no way to meaningfully debug a Web application when the HTML already contains hundreds of bugs.
    • Validate your HTML through an automated service like or other SGML parser. HTML is not “open to interpretation,” as some would like to believe. It’s either right, or it’s wrong.
    • HTML and code produced by automatic tools is often obscure, not human-readable, and introduces its own liabilities. You’ll never be able to debug, fix or secure a page that passes dozens of hidden parameters that are meaningless to a human! (Microsoft Visual InterDev 6 and later are notorious for this!)
    • Learn how HTTP works and how easy it is to exploit!
    • Assume malicious intent and try to break your own site! Assume the user already has your source code. Use all the attacks listed above and send bad data to every parameter your web application uses!
    • Think about how the cookies you send can be used to compromise your site. How will your system react if someone sends you an incorrect or random cookie?
    • Worry about the functionality first and the prettiness last.
    • There’s no substitute for being familiar with what’s going on in HTTP and your web environment. IDEs often obscure implementation details and introduce security issues. Don’t assume that your development environment is doing the “right thing!” I’ve never seen one that does yet!
    • Note that most of these issues are things that can break your web application even if there’s no malicious intent! You have to follow these guidelines when building even completely insecure web applications! Be kind to all the O’Briens in the world!
    • Remember that the most secure network infrastructure with all of the latest firewall, proxy, and encryption techology in the world is rendered completely useless in the presence of a simple application security hole. Fix your application first, because that’s where your interesting and valuable data usually sits.

Leave a Reply

Please log in using one of these methods to post your comment: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s