Page Blocks

Hosting sponsored by:

Point In Space

FWPro Secure Coding Standards


Description

This document describes the data integrity and defensive programming standards to be employed across all FWPro applications to help ensure both a robust user experience in the event of unexpected application or internet services errors and a fundamentally sound application hardened to common flaws and security exposures of insecurely written apps.

Subsequent to this standards spec, a specific testing plan spec should be devised for the methodical testing of any applications. This typical involves testing all form inputs for injections attacks, mal-formed format or data types, performing steps or page selection out of the normal sequence, repeated authorization attempts with incorrect and partially correct credentials, pulling the internet connection at various inoperatune times, etc.

OWASP

The Open Web Application Security Project (OWASP, http://www.owasp.org/) is a community effort to identify generic security vulnerabilities and common development flaws in web applications and promote the principles of application development and execution with best known practices for improving web application security.

Be familiar with everything the OWASP TopTen and latest complete OWASP Guide have to say about web application security. Know it. Breath it. Code it.

The content below is redundant to the OWASP documentation in a number of areas, but is nonetheless provided to be clear about what standards will be required for FWPro applications, and to identify preferred methods or standards where several options are possible. The Coding Standards section is generic to all applications and all languages which may be used. The Language Examples provide language-specific examples of certain principles.

Coding Standards

  1. Principle of least privilege

  1. Each layer of code, each routine, each service is to run with the least amount of privilege required.

  1. For example, code which will only ever perform a search of database should run with a database user profile which only allows searching and has insert and delete capabilities disabled. Same for read and write file access, and same for acquiring or granting network port/protocol access.

  1. Privileged code segments and compartmentalization

  1. Use privilege wrapped code segments for accessing vulnerable services (databases, files, network protocols)

  1. Keep privileged code segments short. Keep privilege wrappers around immediate resource access code only. Don't wrap a whole page or a whole function inside a privileged wrapper when only a small segment of that code needs privileged capability.

  1. For example, consider a routine which selects some data table records, performs some data transformation steps, writes results orstats to a text log, then resaves the new data in a new data table. Instead of wrapping that entire operation in a singe privileged wrapper, use three separate wrappers dedicated to the immediate tasks of the database select, the file access, and the database writing.

  1. Use separate privileges for separate functions (compartmentalization)

  1. Even if a server or language allows for consolidating privileges for services such as database, files, and network access, define separate profile dedicated to each resource.

  1. For example a middleware application srever which allows for distinction of database and file access privileges, do not use a single privilege profile for the whole of the application. Create a profile for file access and another profile for database access and use them for their exclusive concerns.

  1. Create multiple privileged users specific to separate application areas

  1. For example, an application with payroll and inventory areas may each have search-only functionality. Do not define a single search-only database user. Define one search-only user for the payroll application module, and another search-only user for the inventory module. These modules are distinct, and (let's assume) do not have any functionality cross over. Even if the two application segements in fact have the same privilege needs (databases, tables, etc), as the application evolves over time those privileges may diverge for the two application areas, and we do not want the application which should have the lesser scope operating with privileges of the larger scope (as this would violate the principle of least privilege). Therefore, each major module or “sub-application” of a larger application shoud run as unique users dedicated to that portion of the application. Much as we would normalize class and object design into separate concerns, so should privilege profiles be normalized.

  1. Input Validation

  1. All data submitted by the browser regardless of source, pre-validations, or authentications is to be considered untrusted as to integrity of format and data type

  1. All input to the application, be it from web page POST forms, URL GET forms, SOAP or other XML services, or another dynamic source such as uploaded files, and even cookies which the application believes it created, must be validated before the application performs transformation routines or stores the data

  1. Validation of all, repeat, all inputs must be performed using server side code.

  1. Client side validation is acceptable for providing instant user feedback to web forms, but it is not a substitute for server side validation

  1. Validation consists of one or more of the following analytical or scrubbing steps, or any other appropriate action for the input or data type

  1. Test for input data type and format

  1. If inputs are supposed to be integers, test to be sure they're integers. Same for strings, delimited lists, file types, etc.

  1. A variety of standardized data format rules can be defined for data like phone numbers, dates, credit card numbers, etc where spefici formats are required or preferred.

  1. Test for out of bounds values

  1. if the value us supposed to be between 1 and 5, test to ensure the value received is in fact between 1 and 5

  1. HTML value lists are not considered trustworthy either. They can be rewritten client side and submitted to the server with unintended options. Same for XML elements. If there is a specific list of acceptable options, test that the input is indeed a member of that set.

  1. Test for SQL injection

  1. escape quotes, comment symbols, etc. (there are plenty of SQL injection articles, read some, and find ones specific to the database being used)

  1. Test for script injection (XSS)

  1. any string input which may end up being displayed on the web page must be scrubbed for attempts to include HTML, JavaScript or server-side scripting code. Generally, the dynamic language will provide encoding commands which will convert synbols like < and > into HTML entities which will prevent the string from being interpreted as code. Use those commands, or do it manually.

  1. there are numerous artcles about “cross site scripting” (XSS), “script injection,” and “html injection.” Find some. Read them.

  1. Validation code is to be standardized into a reusable library with an assortment of predefined data types and formats. The purpose of this ie to ensure quality of repeatability and reliability of validation processes (and to ensure they're not hand coded on the fly with each data input page).

  1. In addition for data type and format, the server side of the application must know exactly what inputs to expect from a form or a web service packet and process no fewer and no more inputs. Even if inputs are received, they should not be automatically processed. (i.e. do not iterate through an array of submitted inputs, but rather iterate through a server side list of expected inputs and explicitly pull each expected input from the submitted inputs).

  1. Error Handling

  1. Applications are to be written with extensive defensive error testing and failure mode handling

  1. Defensive programming is about planning for the unexpected, and anticipating that things which “cannot” go wrong will in fact go wrong. If the the code does not anticipate those scenarios, unexpected and uncontrolled program execution occurs which leads to unpredictable failures. The more “not supposed to happen” scenarios which can be anticipated and specifially recovered from the more robust (and secure) the application will be. In addition there should be a catch-all layer which fails to a safe-haven page (one in which recursive or compounded errors are not possible, which usually means a hard coded pure HTML page).

  1. All conditionals are be written with fail safe default options

  1. Conditionals which expect a selection from a specific member set are to be written with a default which catches the occurence of the selection not be a in the member set, and proactively determine how that should be handled.

  1. Every database query is to be followed with standardized handling of unexpected errors including unexpected no records found errors to database unavilability.

  1. Every file access is to be followed with standardized handling of unexpected errors including unexpected no file found errors to other file reading/writing errors.

  1. Internal Data Type Validation

  1. With all languages, but especially with loosely typed languages the programmer needs to ensure that data tranformation operations which expect certain data types as operands are in fact those data types. If an array variable is to be iterated, it should be established that the variable is in fact an array.

  1. Program errors caused by data type mismatches must be anticipated as the data source may be from an injection attempt that may have passed through input validation. As with all security matters, the concept of layers applies to inpuut validation. Variable data type validation is the backup layer to specific format and input validation.

  1. Cookies

  1. Do not store account access credentials in Cookies (no, I don't care if it is encrypted, don't do it)

  1. Do not store privileged access session IDs in cookies.

  1. Do not use “Remember Me” cookies to save people from having to login when they visit any section of the site

  1. Site sections that require login, will in fact require login with every visit

  1. User preferences can be stored in cookies to enable preferred behavior only if that information is not required to be treated with security or privacy protocols

  1. Assume cookies will be stolen, and will be reverse engineered. This should not expose the application or the user to any security or privacy risks.

  1. Privileged User Sessions

  1. Upon a successful login, a user session will be created. A session is a time limited connection associated to a specific user through a unique one-time-use ID value. After login, each page access reauthenticates the user. Rather than pass the user's name and password back and forth between the browser and server (which results in excessive exposure), the user's account is stamped with a unique ID, and the ID is passed between the browser and server. Sessions will expire if the user is inactive for a certain period of time. Certain appilcations may even need to enforce a maximum session limit, and either require relogin, or may automate the changing of the session ID on the fly.

  1. Do not store account access credentials in session IDs or tokens (no, I don't care if it is encrypted, don't do it)

  1. Do not store privileged access session IDs in cookies.

  1. Session IDs must use a character space of the entire lowercase and upper case english alphabet and the ten numeric digits, must be case sensitive, and must be at least 32 characters long.

  1. Sessions will expire after a specified time period of inactivity (application configurable in minutes)

  1. Sessions will expire when the user clicks a Logout link

  1. When a logout occurs the application will proactively destroy session data and all cookies created not related to user preferences

  1. For all login required pages (whether HTTP or HTTPS) all known HTTP header/HTML <meta> tag methods will be used to prevent the caching of page data

  1. User Authentication

  1. The following describes the range of features and options that a standardized Authentication system should provide. Not all features are applicable to all applications (some are applicable to intranet environments only), but should be part of a standard code base to ensure stability, reliability, and commonality of codebase among applications. These features are modeled after the fwpAuth_user authenticated user class found in the FWPro framework.

  1. http://www.pageblocks.org/ftrs/api_auth

  1. http://www.pageblocks.org/refc/fwp_user

  1. User authentication involves the process of identifying a remote user. Applications can use user self-approved user accounts or administrator-approved user accounts to establish an authorized user list as appropriate to the application.

  1. Self-signup accounts will require that the user provide a valid email address and that a validation code be supplied in a response email, where that code must then be provided by the user to activate the account

  1. Users will require two pieces of unique information to identify their account at login in the form of an email address and password

  1. Each user account will be defined and stored as an individual database record with:

  1. contact info: usually at least the user name, but can be adjusted as deemed necessary for the application

  1. account info: email address, password, password hint

  1. password values will not be visible to application administrators at any level

  1. password values will never be displayed in clear text in any web page

  1. application permissions: a matrix of data sets and access privileges

  1. refer to User Authorization below for more details

  1. Each user's email address must be unique

  1. Each password/passphrase must conform to the following:

  1. minimum of 8 characters in length

  1. maximum of 64 characters in length

  1. must contain at least one uppercase character (A...Z)

  1. must contain at least one lowercase character (a...z)

  1. must contain at least one numeral character (0...9)

  1. must contain at least one of the following symbol characters (!@#$%^&*) if the overall length of the password is less than 12 characters

  1. All passwords will be stored in MD5 encrypted format

  1. Login attempts will be tracked, and a failure to successfully login after a certain number of attempts will result in a time delay before the user can try to login again (even if the correct access keys are provided)

  1. The number of failed attempts will be adjustable between 1-9, the usual default is 3 times (a value of 0 deactivates this feature)

  1. The duration of the lockout will be adjustable in minutes, the default is 15 minutes (a value of 0 deactivates this feature)

  1. Accounts not logged into for a certain number of days can be automatically deactivated

  1. The number of days is configurable (a value of 0 deactivates this feature)

  1. Deactivated accounts remain in the database, but for intranet type applications require a new password and an administrator flag cleared to be reactivated. User self-signup accounts can either be purged, requiring re-signup, or if appropriate handled by a human admin as described above.

  1. Passwords can be made to expire after a certain number of days regardless of the account being active or inactive (the purpose is to force expire dead accounts and eliminate them as brute force targets)

  1. The number of days is configurable (a value of 0 deactivates this feature)

  1. If password expiration is activated, the user will be able to change his own password during an X day period prior to the expiration date. The user will be reminded of the expiration and promoted to update the password. Passwords not changed before expiration will require administrator reactivation.

  1. The number of days is configurable (subject to password expiration being active)

  1. Passwords can be required to be unique for a certain number of issuances before a prior password may be reused (the purpose is prevent old passwords from being active in the system which helps fight “sticky-note” intrusions)

  1. the number of past passwords remembered by the system is configurable (a value of 0 deactivates this feature)

  1. Passwords assigned by an administrator will be usable for initial login only, the user must supply a new password before continuing to use the application (the purpose here is that even administrators will not know user chosen passwords)

  1. User Authorization

  1. Authorization involves the control of each user's permissions to view and edit specified data. Each user is profiled with data access permissions created by a matrix of application data sets and data access privileges. Data access sets are groups of related information which can viewed or accessed under a single privilege. Data access privileges typically include viewing, adding, updating, and deleting records. Each data set is governed by an independent set of access privileges. A user may be granted permissions to add and update accounting records but only view sales records. This is acheived by explicit functional permissions assigned to the user not by user type or role. These features are modeled after the fwpAuth_user authenticated user class found in the FWPro framework.

  1. http://www.pageblocks.org/ftrs/api_auth

  1. http://www.pageblocks.org/refc/fwp_user

  1. Users can be classified with a user type or role(s) which identifies their professional relationship within the application.

  1. The classification will be used in defining data query filters which limit the record set(s) accessible to that user

  1. Possible classifications are application specific, and the application code will define application data query specific-filters

  1. Query filters are comprised of a filter name (for retrieval identification), the applicable data table, field, match string, and match operator.

  1. Each user, and each role may have multiple filters as required by the application.

  1. Application data and/or features will be logically divided into sets representing collections of fields and/or functions available to specific privilege settings

  1. Users will be granted one or more specific data viewing and/or editing privileges for each data set such as view only, add new records, update existing records, delete existing records

  1. The assignment of user privileges is done on an individual basis (not on a group membership basis)

  1. The application is to be written with privileged features and functions wrapped in the application authorization conditional which tests the logged in user's permissions for access. This can be as broad as a whole page, or as fine-grained as a single field displayed on a page.

  1. (add screenshot of typical user permissions matrix)

  1. (add example schema of FWPro user auth tables)

  1. User and Access Logging

  1. Logging of user access and activities provides a “breadcrumb trail” primarily for tracking suspected unauthorized access. Logs can be written as plain text files or to a database. Additionally, the application also logs unexpected errors to help track suspected coding flaws.

  1. Every login attempt whether successful or unsuccessful is logged

  1. Logged data includes when possible: server date, server time, user login name, session id, user account name, user account record id, user's IP address

  1. Every record creation, modification, deletion is logged

  1. Logged data includes: server date, server time, user account name, user account record id, user's IP address, web page used, an action identifier (add|update|delete), the table modified, the record ID modified

  1. Application level errors are logged

  1. Application internal errors to be rated as to severity with automated support admin notification occuring above an application configurable level

  1. Error ratings to provide at least 5 levels of escalation

  1. All logs are rolled on an application configured frequency

  1. Options include daily, weekly, monthly, annually

  1. Evaluate code for race conditions

  1. Race conditions are the potential for unauthorized / unexpected breaks in the chain of custody of resources in privileged multi-step processes. This condition comes when code wants to access or control a shared resource. The resource must be checked for availability, then must request control. Between those two steps, the resource can change or be hijacked.

  1. These conditions only occur in specialized applications. For more information whether they may apply to any code you are writing, read a few references and review your code for similar situations.

  1. http://www-128.ibm.com/developerworks/library-combined/l-sprace.html

  1. http://en.tldp.org/HOWTO/Secure-Programs-HOWTO/avoid-race.html

  1. Database Design / Form Integration

  1. Do not use autoinc or any sequentially numbered value for a table's primary key. Primary key values are to be random alphanumeric strings of 16 or more characters in length.

  1. HTML forms, web services data schema, or any other input/ouput which involves database table exchange should not use database field names for data element names. Database schema is to be protected as secure information. The application is responsible for internally mapping HTML form inputs or XML data elements to database schema. Aside from security issues, there is the practical aspect that db schema may change, and this should not require a change in I/O interfaces to remain congruently named.

References

links, books, etc

Code Examples

Principle of Least Privilege

The LP8 server uses an administrative application to supervise code execution privileges. Lasso assigns privileges to database hosts, databases, disk files, and specific language tags to a Security Group. An individual Security User with unique name and password credentials are assigned membership into one or more Groups in order to inherit the privileges of that (those) Group(s). Any one Lasso application should have multiple security Groups dedicated to specific concerns. One or more Groups would be assigned to database access (i.e. one Group limited to searching only, another Group with search, add, edit, and delete privileges), and one or more Groups assigned to file access privileges (i.e. one Group for reading root relative config files, one Group for writing root relative files, and another Group specifically used for handling uploaded files).

Privileged Code Segments and Compartmentalization

Lasso uses a container tag named inline: to execute code with the privileges of one of its Security Groups. The inline tag accepts -username and -password parameters to identify a specific Security User which then inherits privileges from the Group(s) it is a member of. Using the example from section 2.2.1, such code could be programmed the following two ways.

INCORRECT: all code is executed with a single privilege wrapper

    // open a privilege code segment and select records
    inline:
        -username    = $lassoUserName,
        -password    = $lassoUserPswd,
        -database    = $applicationDatabase,
        -sql        = $selectQuery;
 
        ..... transformation code working with record results .....
 
        //    now save some stuff to a log
        //    uses the same privileges as the query
        file_setsize: #filePath, 0;
        file_write: #filePath, #fileData, -fileoverwrite;
 
        //    now save transformed to data to database
        //    this inline opens a new query session
        //    but still uses the privileges of the first inline
        inline:
            -database    = $applicationDatabase,
            -sql        = $insertQuery;
        /inline;
    /inline;
        

CORRECT: each code concern is executed with separate and dedicated privilege wrapper

    inline:
        -username    = $dbUserName,
        -password    = $dbUserPswd,
        -database    = $applicationDatabase,
        -sql        = $selectQuery;
    /inline;
 
    ..... transformation code working with record results .....
 
    //    now save some stuff to a log
    //    with a user dedicated to files
    inline:
        -username = $fileUserName,
        -password = $fileUserPswd;
    
        file_setsize: #filePath, 0;
        file_write: #filePath, #fileData, -fileoverwrite;
    /inline
 
    // now save transformed to data to database
    inline:
        -username    = $dbUserName,
        -password    = $dbUserPswd,
        -database    = $applicationDatabase,
        -sql        = $insertQuery;
    /inline;

Defensive Failsafe Error Handling

An example of this type of programming can be made with conditional code. If a decision has to be made based on a string variable being equal to one of two mandatory options of circle or square, non-defensive programming would assume that the variable would always equal to one of the two choices. That might be written as:

    if: $shapeChoice == 'circle';
        ..... do some circle stuff .....
    else: $shapeChoice == 'square';
        ..... do some square stuff .....
    /if;
 
    select: $shapeChoice;
        case: 'circle';
            ..... do some circle stuff .....
        case: 'square';
            ..... do some square stuff .....
    /select;
        

In both of these cases,  if the $shapeChoice var does not contain one of the two expected options, the outcome is unpredictable. Neither of the code blocks will be processed, and code further down the page which depends on that outcome may behave erratically. Best case is an inelegant error for the user, and worst case is some form of security hazard or code exposure if error handling is just as poorly planned. The proper defensive and failsafe way to code these examples is as follows:

    
    if: $shapeChoice == 'circle';
        ..... do some circle stuff .....
    else: $shapeChoice == 'square';
        ..... do some square stuff .....
    else;
        ..... yikes, unexpected value .....
        ..... do some proactive recovery .....
    /if;
 
    select: $shapeChoice;
        case: 'circle';
            ..... do some circle stuff .....
        case: 'square';
            ..... do some square stuff .....
        case;
            ..... yikes, unexpected value .....
            ..... do some proactive recovery .....
    /select;

 

In these cases, the solution is to provide a default condition case which traps all “other” values which we interpret as unknown and meaningless, but from which we need to recover with some control.

Other examples of defensve programming is anticipating database errors with every single query. The database may be offline, there may be a transaction failure and a record that is “supposed to be there” just isn't which generates a no records found error.


History:

  • first release draft Apr 27, 2005 (Greg Willits)


© 2002-2012, pageblocks.org