Core Security Patterns: Best Practices and Strategies for J2EE, Web Services, and Identity Management

This section discusses best practices and the associated pitfalls regarding securing the Business tier. The best practices have been broken down by layer and are followed by the pitfalls.

Infrastructure

  1. Agent-based policy enforcement. Developers can use agents to enforce policies instead of writing custom code for policy enforcement. Application Server agents are good ways to take advantage of the J2EE container-managed security model while leveraging existing third-party security products.

  2. Access protection. Make sure that a secure java.policy file is in place that enforces access privileges and permissions to protect the JAR components deployed by the application server. Make sure no untrusted JAR files are deployed. This secures JAR/Class files from downloading by hackers and external applications. Make use of digitally signed JAR files so that the code is downloaded by the coexisting application and the owner of the JAR file.

  3. Access restriction to Naming services. Restrict anonymous access to the naming services. Secure the access to the naming services provider by defining only an administrator who can add or remove services from the JNDI registry. Allow application-level access to lookup, bind, and rebind with services.

  4. Error reporting. Always return an error page or exception specific to the application error and the user's request. For example, you might use an application-specific InvalidUserException and NoAccessPrivilegesException. Do not expose remote, system-level, and naming service specific exceptions to the user accessing the applications. These exceptions to the end user expose weakness in the application and allow hackers to design potential attacks.

  5. Database communication. Make use of the database provider's recommended security mechanisms for persisting data. Adopt possible options to improve the transport and data security, such as encrypting communication and sensitive data before writing it to the database. For example, store customer data in the database in plain text except for the encrypted credit card information.

Architecture

  1. Component protection. Make sure all business components are protected with security roles and appropriate privileges before deployment. Avoid defining a global security role such as administrator unless it is warranted by the application.

  2. Role mappings. Adopt dynamic role mappings based on business rules, the context of the request, or a condition such as access hours, time of day, group membership, specific assignment, or a caller member of the group. For example, a user may be allowed to be in an administrator role only while the actual administrator is away, as a temporary arrangement, by adding the user to a special role or group. You must be able to specify the hours between which the temporary administrator has special privileges. These privileges are automatically revoked when the time expires or the actual administrator returns. You also want to avoid using the same role names in the application because application-specific roles are mapped in deployment descriptors and they should be different from LDAP roles.

  3. Rich-client authentication. While accessing EJB components via rich Java clients, do not send username/password credentials of the user through a Java object. Adopt container-managed mechanisms and then use declarative or programmatic security mechanisms to obtain the associated principal from them.

  4. MDB access. Restrict unauthorized access to the MDB and prevent it from sending and processing malicious messages. Make sure the message sender uses a unique message ID, correlation IDs, and custom message headers to verify the sender's authenticity before processing the message.

  5. Secure auditing. Deploy a secure logging and auditing mechanism (Audit Interceptor) to record and to provide a means of identifying and auditing all direct access attempts, policy violations, failed authentication attempts, failed EJB access, and exceptions.

  6. Principal propagation. In the case of defining delegated associations between EJBs and trust relationships between containers, it is necessary to analyze the consequences and potential risks of using the runAs technique for principal delegation and for propagating identity. SSL Mutual authentication is the best approach before initiating communication for exploring trust relationships between containers.

  7. Securing Business Tier components. Use the Secure Session Façade to protect interactions and to mask the exposure of underlying business components and their methods.

  8. Data validation. Adopt well-defined validation procedures in the business component for handling data-format and business data. This ensures data integrity and protects application components from the risk of processing overhead due to malicious data injection.

  9. Data obfuscation. Adopt object obfuscation (Obfuscate Transfer Object) while using value objects that represent a snapshot of security-sensitive data in the database.

Policy

  1. Disallow unnecessary protocols. In cases where rich clients are not being used to access business components, disallow all traffic from ports specific to RMI/IIOP, IIOP-CSIv2, or J2EE vendor-preferred protocols. Also disallow all service requests, routing information, and packet content from external access to EJBs or business components.

  2. Restrict deployed components. Do not store undeployed business components in the production environment.

  3. Restrict user access. Configure user lockouts and access time limits to prevent attacks from potential hackers on user accounts that send malicious data. Avoid long-duration transactions that affect performance.

  4. Authentication enforcement. Use a Secure Session Object to provide authentication enforcement in the Business tier. This prevents circumvention of Web-tier controls by preventing any communication with the Business tier (for example, a direct EJB invocation via RMI) from an external source without proper authentication.

  5. Use Audit Interceptor to audit events. Properly audit events and have formal audit reviews to ensure the application has not been compromised. Have a process and procedures in place to diagnose the audit logs in the case of a disaster or attack.

  6. Monitor for malicious activity. Use Dynamic Service Management to monitor security-related components. Build or buy a tool that provides automated monitoring of those components in a way that lets you detect malicious activity. For example, set a threshold with an alert on the number of incorrect logins per user client to detect a hacker using a brute force password attack or attempting to scan for weak passwords across accounts.

Pitfalls

  1. Build versus buy. Developers tend to build versus buy solutions because doing so gives them maximum flexibility and allows them to maintain control. This is usually a bad practice, because the costs of additional time and resources outweigh the benefits of the flexibility. In the case of security, this is especially true. Most developers do not understand all of the security issues well enough to implement a security model better than a vendor. A vendor product has the added benefit of being time-tested in the real world with feedback from external sources.

  2. Performance risks. The principle of conservation of energy demonstrates that you cannot get something for nothing. This holds true for security. The cost for increased security usually comes at the price of performance. While it is necessary to achieve a certain level of security, introducing unnecessary security functionality usually reduces performance and increases complexity. Strive to balance security and performance in your applications.

Категории