ESAPI를 이용한 OWASP Top 취약점 예방

원본: http://amtuanand.blogspot.kr/2012/01/owasp-top-vulnerabilities-and.html

 

ESAPI를 이용한 OWASP Top 취약점 예방

 

 

1. Authentication 

 

ESAPI Autentication 인터페이스는 계정의 자격증명이나 세션 구분자을 생성하거나 조작할 수 있는 메서드 모음을 정의한다. ESAPI의 authenticatior  클래스 객체는 다음과 같이 생성할 수 있다. 

 

Authenticator instance = ESAPI.authenticator();

 

사용자 생성


 

ESAPI에서 사용자를 생성하는 방법은 두가지 이다.

애플리케이션 안에서 다음과 같이 사용자를 생성할 수 있다. 

ESAPI.authenticator.createUser(username, password, password)

새로운 사용자를 생성하기 위한 정보를 제공한다. 생성할 사용자의 이름과 패스워드(패스워드는 brute force 공격에 취약하지 않은 강도를 가지고 있는지 점검한다. verifyAccountNameStrength(String), verifyPasswordStrength(String, String) )   새로운 패스워드의 두개 복사본은 사용자 계정생성시 입력되는  re-type password가 포함되도록 설계된 것이다.

 

 Note: createUser()로 생성되는 사용자는 디폴트로 disabled 하거나 locked 시킬 수 있다.


ESAPI.authenticator().getUser(username).enable();
ESAPI.authenticator().getUser(username).unlock();


Login

디폴트 ESAPI authenticator를 사용하려면 로그인페이지는 SSL을 사용해야 하며, 서버는 SSL을 설정을 위한 keystore 파일을 가지고 있어야 한다.


인증을 사용하기 위해 다음과 같이 호출한다.

User user = ESAPI.authenticator().login(HTTPServletRequest, HTTPServletResponse);

UsernameParameterName과 PasswordParameterName 변수는 ESAPI.properties에 미리 설정되어 있어야 한다. login() 메서드는 HTTPRequest로 부터 username과 password값을 프로퍼티에 미리 설정된 변수명으로 참조한다.


Logout

사용자가 로그아웃을 하기 위해서는 다음과 같이 간단히 호출하면 된다.


User user = ESAPI.authenticator().logout;


ESAPI User Interface

ESAPI의 User 인터페이스는  응용프로그램이 보안을 강화하기 위해 각 사용자에 대해 저장해야 하는 많은 정보를 저장할 수 있도록 지원한다. 사용자 계정은 여러가지 상태중 하나 일 수 있다. 계정을 처음 만들때 사용자는 비활성화 되어야 하고,  만료되지 않아야 하고, 락되지 않아야 한다. 계정을 사용하려면 관리자는 계정을 사용가능하도록 설정해 주어야 한다. 계정이 락이 되는 경우는 너무많은 로그인 시도가 있은경우가 가장 일반적인 이유이다. 만료날짜가 되는 경우도 계정이 잠기게 된다. 사용자 인증을 통해 User는 enable, not expired, unlock 상태를 얻을 수 있다.


2. Session Management

Session management 는 컴퓨터 시스템과 상호 작용하는  사용자의 활동을  추적하는 과정이다.  ESAPI 의 HTTPUtilities 인터페이스는 HTTP 요청, 응답, 세션, 쿠키, 헤더, 로깅에 관련된 추가 보안을 제공하는 방법의 모음이다.


Session Fixation

인증할 때마다 응용 프로그램이 사용하는 세션 식별자를 변경해야 세션 하이재킹 공격의 취약점을 제거할 수 있다.  공격자가 다른 사용자의 세션식별자를 알고 있다면 해당 세션 식별자를 사용하여 다른 사용자의 권한으로 서비스를 받는것이 가능하게 된다. 처음 할당 받은 세션식별자가 변경되지 않고 세션동안 계속 유효하게 사용할 수 있는것을  "session fixation" 이라고 부른다.


사용자가 로그인 할대 세션 식별자를 변경하게 되면 쉽게 공격자를 무력화 시킬 수 잇다. 하지만 대부분의 플랫폼이 기본적으로 이 작업을 수행하지 않는다. ESAPI를 사용하여 사용하여 인증작업을 수행하게 되면 쉽게 "Session Fixed" 취약점을 제거할 수 있다.


ESAPI.httpUtilities().changeSessionIdentifier();


사용자가 로그아웃할 때 마다 세션 식별자가 서버에서 무효화 되고, 브라우저에서 클리어 되는지 확인해야 한다.

 



Cross Site Request Forgery

CSRF는 현재 인증되어 있는 사용자가 의도하지 않은 액션을 강제로 수행하게 하는 공격이다.  사회공학(이메일이나 링크등)의 도움으로 공격자는 공격자가 원하는 작업을 사용자가 실행하도록 한다. 성공적인 CSRF공격은 결국 사용자 데이터의 손상을 유발 할 수 있으며, 만약 공격 대상이 관리자라고 한다면 전체 웹 애플리케이션의 손상도 발생될 수 있다. CSRF 토큰을 사용하여 해당 요청이 실제 해당 사용자의 요청인지를 확인하는 단계를 추가하여 이 공격을 회피할 수 있다.

ESAPI.httpUtilities().addCSRFToken()

A CSRF 토큰은 세션마다 또는 하나의 요청마다 새로 생성하여 사용할 수 있다.

ESAPI.authenticator().getCurrentUser().resetCSRFToken()


3. Access Control

 

Access Control은 시스템에서 각 사용자의 권한을 정의하는 프로세스이다. ESaPI Access Controller 인터페이스는 액세스 제어를 수행하는 다양한 애플리케이션에서 사용할 수 있는 메서드들을 정의하고 있다.

 


Preventing Forced Browsing

 

AccessController 인터페이스는 액세스 제어를 수행하는 다양한 애플리케이션에서 사용할할 수 있는 다양한 메서드들을 정의하고 있다.  대부분의 애플리케이션에서 다양한 응용 계층의 여러 위치에서 수행되어야 한다.  이 클래스는 URL들이나, 비즈니스 기능, 데이터, 서비스, 파일을 위한 액세스 제어 기능을 제공한다.

 

ESAPI.accessController().isAuthorizedForURL(String url)
<-- 계정이 참조하는 URL에 접근 권한이 있으면 true를 반환한다. URL 접근 권한 룰은  .esapi\fbac-policies\URLAccessRules.txt  파일에 정의한다.

 

ESAPI Access Controller 인터페이스는 다음과 같은 메서드를 정의하고 있다.


 

  • assertAuthorizedForData(java.lang.String key) Checks if the current user is authorized to access the referenced data. This method simply returns if access is authorized.
  • assertAuthorizedForData(java.lang.String action, java.lang.Object data) Checks if the current user is authorized to access the referenced data.
  • assertAuthorizedForFile(java.lang.String filepath) Checks if an account is authorized to access the referenced file.
  • assertAuthorizedForFunction(java.lang.String functionName)Checks if an account is authorized to access the referenced function.
  • assertAuthorizedForService(java.lang.String serviceName) Checks if an account is authorized to access the referenced service.
  • assertAuthorizedForURL(java.lang.String url) Checks if an account is authorized to access the referenced URL.
  • boolean isAuthorizedForData(java.lang.String key) Checks if an account is authorized to access the referenced data, represented as a String.
  • boolean isAuthorizedForData(java.lang.String action, java.lang.Object data) Checks if an account is authorized to access the referenced data, represented as an Object.
  • boolean isAuthorizedForFile(java.lang.String filepath) Checks if an account is authorized to access the referenced file.
  • boolean isAuthorizedForFunction(java.lang.String functionName) Checks if an account is authorized to access the referenced function.
  • boolean isAuthorizedForService(java.lang.String serviceName) Checks if an account is authorized to access the referenced service.
  • boolean isAuthorizedForURL(java.lang.String url) Checks if an account is authorized to access the referenced URL.

Preventing Insecure Object References

 

개발자가 같은 URL이나 폼 매개 변수로 파일, 디렉토리, 데이터베이스 기록, 또는 키 같은 내부 구현 객체에 대한 참조를 노출 할 때 직접 객체 참조가 발생한다. 액세스 제어가 적절한 위치에서 이루어 지지 않으면 공격자는 권한없이 다른 객체를 액세스하는 직접 객체참조를 조작할 수 있다.

org.owasp.esapi.reference.RandomAccessReferenceMap을 사용하여 direct 참조에서 indirect 참조로 변경할 수 있다. 내부의 직접 객체 참조 집합을 안전한 간접 참조 집합 으로 매핑하는데 사용된다. 데이터베이스의 키나 파일명, 다른 타입의 직접 객체참조에 사용될 수 있다. 규칙에 의해 개발자는 공격자가 조작하려고 시도하는 직접 참조 객체에 대한 노출을 제거할 수 있다.

 


4. Input Validation


입력 유효성 검사는 프로그램이 정확하고 유용한 데이터에서 작동되도록 하는 프로세스이다 ESAPI validator 인터페이스는 신뢰할 수 없는 입력을 정규화하고 유효성 검사를 수행하는 메서드의 집합이다.  입력값의 유효성 검사는 애플리케이션 보안의 기본이다.


가장 일반적인 웹 애플케이션 보안 취약점은 클라이언트 또는 환경으로 부터 입력되는 입력값에 대한 유효성 검사가 제대로 이루어지지 않은 경우 발생한다. 클라이언트는 데이터를 조작할 수 있는 가능성이 있으므로 클라이언트에서 전송되는 데이터는 신뢰할 수 없다.


인코딩은 입력 유효성 검사의 부족에 의존하는 공격을 완화 시킬 수 있다. 브라우저로 전송되기 전에 사용자의 입력을 HTML 엔티티 인코딩을 사용하는 경우 대부분의 XSS 공격을 방지할 수 있다.  하지만 단순한 공격 예방만으로 충분하지 않으므로 침입탐지를 수행하는 기능이 애플리케이션에 포함되어야 한다. 


Validating User Input

Validator interfaces는 신뢰할 수 없는 입력을 정규화하고, 유효성을 검사하는 메서드의 집합을 정의한다.  이 인터페이스는 예외를 발생시키기 보다는 부울값을 결과로 반환한다. 

ESAPI.validator().getValidInput(String context,String input,String type,int maxLength,
                                               boolean allowNull,ValidationErrorList errorList)

이 메서드는 정규화되고 검증된 입력데이터를 문자열로 반환한다. 잘못된 입력은 ValidationException을 발생시키며, 명확하게 공격 데이터 인 경우 IntrusionException을 발생시킨다. 에러는 ValidationErrorList 에 저장된다. 

ESAPI.validator().getValidInput 은 validation.properties에 기술된 Validator.SafeString으로 정의된 정규표현식을 사용하여 검증한다. 

1. 입력은  ESAPI.validator().getValidInput() 을 사용하여 정규화와 검증 작업을 수행한다.

2. 출력은 XSS 방지하기 위해 ESAPI.encoder().encodeForHTML() 을 사용한다.

ESAPI's Validator Interface는 다음 메서드들을 포함한다.
  • void assertIsValidHTTPRequest() Validates the current HTTP request by comparing parameters, headers, and cookies to a predefined whitelist of allowed characters.
  • void assertIsValidHTTPRequestParameterSet(String context, Set required, Set optional) Validates that the parameters in the current request contain all required parameters and only optional ones in addition.
  • void assertIsValidHTTPRequestParameterSet(String context, Set required, Set optional, ValidationErrorList errorList) Validates that the parameters in the current request contain all required parameters and only optional ones in addition.
  • void assertValidFileUpload(String context, String filepath, String filename, byte[] content, int maxBytes, boolean allowNull) Validates the filepath, filename, and content of a file.
  • void assertValidFileUpload(String context, String filepath, String filename, byte[] content, int maxBytes, boolean allowNull, ValidationErrorList errorList) Validates the filepath, filename, and content of a file.
  • String getValidCreditCard(String context, String input, boolean allowNull) Returns a canonicalized and validated credit card number as a String.
  • String getValidCreditCard(String context, String input, boolean allowNull, ValidationErrorList errorList) Returns a canonicalized and validated credit card number as a String.
  • Date getValidDate(String context, String input, java.text.DateFormat format, boolean allowNull) Returns a valid date as a Date.
  • Date getValidDate(String context, String input, java.text.DateFormat format, boolean allowNull, ValidationErrorList errorList) Returns a valid date as a Date.
  • String getValidDirectoryPath(String context, String input, boolean allowNull) Returns a canonicalized and validated directory path as a String. Returns a canonicalized and validated directory path as a String.
  • String getValidDirectoryPath(String context, String input, boolean allowNull, ValidationErrorList errorList) Returns a canonicalized and validated directory path as a String.
  • Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) Returns a validated real number as a double.
  • Double getValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull, ValidationErrorList errorList) Returns a validated real number as a double.
  • byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) Returns validated file content as a byte array.
  • byte[] getValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull, ValidationErrorList errorList) Returns validated file content as a byte array.
  • String getValidFileName(String context, String input, boolean allowNull) Returns a canonicalized and validated file name as a String.
  • String getValidFileName(String context, String input, boolean allowNull, ValidationErrorList errorList) Returns a canonicalized and validated file name as a String.
  • String getValidInput(String context, String input, String type, int maxLength, boolean allowNull) Returns canonicalized and validated input as a String.
  • String getValidInput(String context, String input, String type, int maxLength, boolean allowNull, ValidationErrorList errorList) Returns canonicalized and validated input as a String.
  • Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) Returns a validated integer.
  • Integer getValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull, ValidationErrorList errorList) Returns a validated integer.
  • String getValidListItem(String context, String input, List list) Returns the list item that exactly matches the canonicalized input.
  • String getValidListItem(String context, String input, List list, ValidationErrorList errorList) Returns the list item that exactly matches the canonicalized input.
  • Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) Returns a validated number as a double within the range of minValue to maxValue.
  • Double getValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull, ValidationErrorList errorList) Returns a validated number as a double within the range of minValue to maxValue.
  • byte[] getValidPrintable(String context, byte[] input, int maxLength, boolean allowNull) Returns canonicalized and validated printable characters as a byte array.
  • byte[] getValidPrintable(String context, byte[] input, int maxLength, boolean allowNull, ValidationErrorList errorList) Returns canonicalized and validated printable characters as a byte array.
  • String getValidPrintable(String context, String input, int maxLength, boolean allowNull) Returns canonicalized and validated printable characters as a String.
  • String getValidPrintable(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) Returns canonicalized and validated printable characters as a String.
  • String getValidRedirectLocation(String context, String input, boolean allowNull) Returns canonicalized and validated printable characters as a String.
  • String getValidRedirectLocation(String context, String input, boolean allowNull, ValidationErrorList errorList) Returns canonicalized and validated printable characters as a String.
  • String getValidSafeHTML(String context, String input, int maxLength, boolean allowNull) Returns canonicalized and validated "safe" HTML.
  • String getValidSafeHTML(String context, String input, int maxLength, boolean allowNull, ValidationErrorList errorList) Returns canonicalized and validated "safe" HTML.
  • boolean isValidCreditCard(String context, String input, boolean allowNull) Returns true if input is a valid credit card.
  • boolean isValidDate(String context, String input, java.text.DateFormat format, boolean allowNull) Returns true if input is a valid date according to the specified date format.
  • boolean isValidDirectoryPath(String context, String input, boolean allowNull) Returns true if input is a valid directory path.
  • boolean isValidDouble(String context, String input, double minValue, double maxValue, boolean allowNull) Returns true if input is a valid double within the range of minValue to maxValue.
  • boolean isValidFileContent(String context, byte[] input, int maxBytes, boolean allowNull) Returns true if input is valid file content.
  • boolean isValidFileName(String context, String input, boolean allowNull) Returns true if input is a valid file name.
  • boolean isValidFileUpload(String context, String filepath, String filename, byte[] content, int maxBytes, boolean allowNull) Returns true if a file upload has a valid name, path, and content.
  • boolean isValidHTTPRequest() Validate the current HTTP request by comparing parameters, headers, and cookies to a predefined whitelist of allowed characters.
  • boolean isValidHTTPRequestParameterSet(String context, Set required, Set optional) Returns true if the parameters in the current request contain all required parameters and only optional ones in addition.
  • boolean isValidInput(String context, String input, String type, int maxLength, boolean allowNull) Returns true if input is valid according to the specified type.
  • boolean isValidInteger(String context, String input, int minValue, int maxValue, boolean allowNull) Returns true if input is a valid integer within the range of minValue to maxValue.
  • boolean isValidListItem(String context, String input, List list) Returns true if input is a valid list item.
  • boolean isValidNumber(String context, String input, long minValue, long maxValue, boolean allowNull) Returns true if input is a valid number within the range of minValue to maxValue.
  • boolean isValidPrintable(String context, byte[] input, int maxLength, boolean allowNull) Returns true if input contains only valid printable ASCII characters (32-126).
  • boolean isValidPrintable(String context, String input, int maxLength, boolean allowNull) Returns true if input contains only valid printable ASCII characters (32-126).
  • boolean isValidRedirectLocation(String context, String input, boolean allowNull) Returns true if input is a valid redirect location, as defined by "ESAPI.properties".
  • boolean isValidSafeHTML(String context, String input, int maxLength, boolean allowNull) Returns true if input is "safe" HTML.
  • boolean safeReadLine(InputStream inputStream, int maxLength) Reads from an input stream until end-of-line or a maximum number of characters.
One method many people use to safeguard their application from a XSS attack is to filter out the <script> tag. While this may seem like it would prevent an attack involving javascript, it does contain some flaws. One way to bypass this filtering is to input <scr<script>ipt>. When <script> is removed, the two halves of the other <script> tag will come together, forming an attack. Try this below and see what happens.
Use ESAPI.validator().getValidSafeHtml to prevent the Cross Site Scripting Attack.

5. Output Encoding/Escaping

Encoding is the process of transforming information from one format into another. The ESAPI Encoder interface contains a number of methods for decoding input and encoding output so that it will be safe for a variety of interpreters.

Encoding, closely related to Escaping is a powerful mechanism to help protect against many types of attack, especially injection attacks and Cross-site Scripting (XSS). Essentially, encoding involves translating special characters into some equivalent that is no longer significant in the target interpreter. So, for example, using HTML entity encoding before sending untrusted data into a browser will protect against many forms of Cross-site Scripting (XSS).

Considerations:

What interpreter?: To encode properly, you need to know what interpreters the data might end up in. For example, if the data is going into a SQL interpreter, you should consider encoding based on syntax of the SQL engine you are using.

What characters? Complete?:You want to make sure that you encode all the characters that might cause a problem, so the best approach is to use a positive encoding scheme, where all characters except a minimal known good set are encoded.

What encoding scheme?:There are dozens of ways to encode characters and many interpreters allow multiple forms of a single significant character. For a browser, HTML entity encoding is a good way to prevent script injection, but URL encoding or Unicode encoding (%xx) will not prevent scripts from running. Be sure to use the appropriate encoding scheme for the target interpreter.

Double encoding and decoding?:Be careful not to double encode your data. In some cases, doubly encoding data can inadvertently introduce special characters in the final output. Also, be aware that some processors may automatically undo your encoding. There is some evidence that XML processors are decoding HTML entity encoding, thus reintroducing potential XSS problems.

Encoding & Decoding

ESAPI's Encoder interface 입력 인코딩과 출력 인코딩을 위한 메서드를 정의한다.


// ESAPI's Encoder interface 사용예

 

ESAPI.encoder().encodeForHTML(input)


  • String canonicalize(String input) This method performs canonicalization on data received to ensure that it has been reduced to its most basic form before validation.
  • String canonicalize(String input, boolean strict) This method performs canonicalization on data received to ensure that it has been reduced to its most basic form before validation.
  • decodeFromBase64(String input) Decode data encoded with BASE-64 encoding.
  • decodeFromURL(String input) Decode from URL.
  • encodeForBase64(byte[] input, boolean wrap) Encode for Base64.
  • encodeForCSS(String input) Encode data for use in Cascading Style Sheets (CSS) content.
  • encodeForDN(String input) Encode data for use in an LDAP distinguished name.
  • encodeForHTML(String input) Encode data for use in HTML using HTML entity encoding.
  • encodeForHTMLAttribute(String input) Encode data for use in HTML attributes.
  • encodeForJavaScript(String input) Encode data for insertion inside a data value in JavaScript.
  • encodeForLDAP(String input) Encode data for use in LDAP queries.
  • encodeForOS(Codec codec, String input) Encode for an operating system command shell according to the selected codec (appropriate codecs include the WindowsCodec and UnixCodec).
  • encodeForSQL(Codec codec, String input) Encode input for use in a SQL query, according to the selected codec (appropriate codecs include the MySQLCodec and OracleCodec).
  • encodeForURL(String input) Encode for use in a URL.
  • encodeForVBScript(String input) Encode data for insertion inside a data value in a Visual Basic script.
  • encodeForXML(String input) Encode data for use in an XML element.
  • encodeForXMLAtribute(String input) Encode data for use in an XML attribute.
  • encodeForXPath(String input) Encode data for use in an XPath query.
  • normalize(String input) Reduce all non-ascii characters to their ASCII form so that simpler validation rules can be applied.



정규화작업을 수행한뒤 인코딩을 수행하려면 다음과 같이 사용한다.

ESAPI.encoder().canonicalize(input, true);



XSS Prevention

 

A. JavaScript Escape Before Inserting Untrusted Data into HTML JavaScript Data Values
     ESAPI.encoder().encodeForJavaScript(input31)


B. HTML Escape Before Inserting Untrusted Data into HTML Element Content
     ESAPI.encoder().encodeForHTML(input1)


C. Attribute Escape Before Inserting Untrusted Data into HTML Common Attributes
     ESAPI.encoder().encodeForHTMLAttribute(input21)

D. CSS Escape Before Inserting Untrusted Data into HTML Style Property Values
     ESAPI.encoder().encodeForCSS(input41)

E. URL Escape Before Inserting Untrusted Data into HTML URL Attributes
     ESAPI.encoder().encodeForURL(input51)


6. Cryptography

 

Encryption is the process of transforming information (referred to as plaintext) using an algorithm (called cipher) to make it unreadable to anyone except those possessing special knowledge, usually referred to as a key. The ESAPI Encryptor interface provides a set of methods for performing common encryption, random number, and hashing operations.
The failure to encrypt data passes up the guarantees of confidentiality, integrity, and accountability that properly implemented encryption conveys.


Consequences

Confidentiality: Properly encrypted data channels ensure data confidentiality.
Integrity: Properly encrypted data channels ensure data integrity.
Accountability: Properly encrypted data channels ensure accountability.

Risk
Omitting the use of encryption in any program which transfers data over a network of anykind should be considered on par with delivering the data sent to each user on the local networks of both the sender and receiver.
Worse, this omission allows for the injection of data into a stream of communication between two parties - with no means for the victims to separate valid data from invalid.

Encryption

Encryptor interface는 일반적인 암호화, 난수, 해시 작업을 수행하기 위한 메서드를 정의한다.

ESAPI encryption & decryption 메서든는 다음은 기본메서드를 사용한다.


java.lang.String decrypt(java.lang.String ciphertext)

java.lang.String encrypt(java.lang.String plaintext)


ESAPI's encryptor interface을 이용하여 Encryption & decryption 을 수행하려면 다음과 같이 사용한다.

encrypted = ESAPI.encryptor().encrypt( decrypted );
decrypted = ESAPI.encryptor().decrypt( encrypted );


Expiring Data

Create Seal

An integrity seal is created for the plain text entered by the user, the seal is set to be valid for 15 seconds by default.

ESAPI.encryptor.seal( plaintext, instance.getTimeStamp() + 1000 * Integer.parseInt(timer) );

Verify Seal
The call to the following method will return true if the seal is verified within 15 seconds.

ESAPI.encryptor.verifySeal( toVerify );


Unseal

The call to the following method will unseal it back to the plain text if it is done within 15 seconds.

ESAPI.encryptor.unseal(sealed);


ESAPI' Encryptor interface의 다음 메서드들은 Integrity Seals에 사용된다.

  • getRelativeTimeStamp(long offset) Gets an absolute timestamp representing an offset from the current time to be used by other functions in the library.
  • long getTimeStamp() Gets a timestamp representing the current date and time to be used by other functions in the library.
  • String hash(java.lang.String plaintext, java.lang.String salt) Returns a string representation of the hash of the provided plaintext and salt.
  • String seal(java.lang.String data, long timestamp) Creates a seal that binds a set of data and includes an expiration timestamp.
  • String sign(java.lang.String data) Create a digital signature for the provided data and return it in a string.
  • String unseal(java.lang.String seal) Unseals data (created with the seal method) and throws an exception describing any of the various problems that could exist with a seal, such as an invalid seal format, expired timestamp, or decryption error.
  • boolean verifySeal(java.lang.String seal) Verifies a seal (created with the seal method) and throws an exception describing any of the various problems that could exist with a seal, such as an invalid seal format, expired timestamp, or data mismatch.
  • boolean verifySignature(java.lang.String signature, java.lang.String data) Verifies a digital signature (created with the sign method) and returns the boolean result.


Randomness

Insecure randomness errors occur when a function that can produce predictable values is used as a source of randomness in security-sensitive context.

Computers are deterministic machines, and as such are unable to produce true randomness. Pseudo-Random Number Generators (PRNGs) approximate randomness algorithmically, starting with a seed from which subsequent values are calculated.
There are two types of PRNGs: statistical and cryptographic. Statistical PRNGs provide useful statistical properties, but their output is highly predictable and forms an easy to reproduce numeric stream that is unsuitable for use in cases where security depends on generated values being unpredictable. Cryptographic PRNGs address this problem by generating output that is more difficult to predict. For a value to be cryptographically secure, it must be impossible or highly improbable for an attacker to distinguish between it and a truly random value. In general, if a PRNG algorithm is not advertised as being cryptographically secure, then it is probably a statistical PRNG and should not be used in security-sensitive contexts.

Examples:


The following code uses a statistical PRNG to create generate a pseudo-random number.


int GenerateRandomNumber() {
    Random ranGen = new Random();
    ranGen.setSeed((new Date()).getTime());
    return (ranGen.nextInt(400000000));
}


This code uses the Random.nextInt() function to generate "unique" identifiers for the receipt pages it generates. Because Random.nextInt() is a statistical PRNG, it is easy for an attacker to guess the strings it generates. Although the underlying design of the receipt system is also faulty, it would be more secure if it used a random number generator that did not produce predictable receipt identifiers, such as a cryptographic PRNG.
The Randomizer interface defines a set of methods for creating cryptographically random numbers and strings. Implementers should be sure to use a strong cryptographic implementation, such as the JCE or BouncyCastle. Weak sources of randomness can undermine a wide variety of security mechanisms.

ESAPI's Randomizer Interface 는 다음 메서드를 정의하고 있다.


  • boolean getRandomBoolean() Returns a random boolean.
  • String getRandomFilename(String extension) Returns an unguessable random filename with the specified extension.
  • String getRandomGUID() Generates a random GUID.
  • int getRandomInteger(int min, int max) Gets the random integer.
  • long getRandomLong() Gets the random long.
  • float getRandomReal(float min, float max) Gets the random real.
  • String getRandomString(int length, char[] characterSet) Gets a random string of a desired length and character set.

ESAPI Encryptor Configuration

This requires the presence of the encryption keys in the ESAPI.properties file.
The string-based encrypt() and decrypt() methods have been deprecated in favor of the new CipherText-based methods:

ESAPI.encryptor().encrypt(PlainText plainText)
ESAPI.encryptor.decrypt(CipherText ciphertext)

다양한 랜덤 데이터 생성예:
  • ESAPI.randomizer().getRandomBoolean()
  • ESAPI.randomizer().getRandomFilename(request.getParameter("fileExtension"));
  • ESAPI.randomizer().getRandomInteger(min , max)
  • ESAPI.randomizer().getRandomReal(minFloat, maxFloat)
  • ESAPI.randomizer().getRandomString(length, charSet)
  • ESAPI.randomizer().getRandomLong()

7. Error Handling and Logging

Error handling refers to the anticipation, detection, and resolution of programming, application, and communications errors. Data logging is the process of recording events, with an automated computer program, in a certain scope in order to provide an audit trail that can be used to understand the activity of the system and to diagnose problems.


Logging

The ESAPI Logger interface defines a set of methods that can be used to log security events. The ESAPI Logger promotes secure logging functionality while allowing organizations to choose their own logging framework. The primary benefit of the ESAPI Logger is the addition of relevant security information to the log message and the use of specific tags that allow log messages to be identified as SECURITY related (as opposed to FUNCTIONAL, PERFORMANCE, etc).
The Logger interface defines a set of methods that can be used to log security events. It supports a hierarchy of logging levels which can be configured at runtime to determine the severity of events that are logged, and those below the current threshold that are discarded.

ESAPI also allows for the definition of the type of log event that is being generated. The Logger interface predefines 4 types of Log events: SECURITY_SUCCESS, SECURITY_FAILURE, EVENT_SUCCESS, EVENT_FAILURE. Implementations can extend or change this list if desired. This Logger allows callers to determine which logging levels are enabled, and to submit events at different severity levels.

Implementors of this interface should:

  • provide a mechanism for setting the logging level threshold that is currently enabled. This usually works by logging all events at and above that severity level, and discarding all events below that level. This is usually done via configuration, but can also be made accessible programmatically.
  • ensure that dangerous HTML characters are encoded before they are logged to defend against malicious injection into logs that might be viewed in an HTML based log viewer.
  • encode any CRLF characters included in log data in order to prevent log injection attacks.
  • avoid logging the user's session ID. Rather, they should log something equivalent like a generated logging session ID, or a hashed value of the session ID so they can track session specific events without risking the exposure of a live session's ID.
  • record the following information with each event: identity of the user that caused the event,a description of the event (supplied by the caller),whether the event succeeded or failed (indicated by the caller), severity level of the event (indicated by the caller), that this is a security relevant event (indicated by the caller), hostname or IP where the event occurred (and ideally the user's source IP as well),a time stamp.
  • Custom logger implementations might also filter out any sensitive data specific to the current application or organization, such as credit cards, social security numbers, etc. There are both Log4j and native Java Logging default implementations. JavaLogger uses the java.util.logging package as the basis for its logging implementation. Both default implementations implements requirements #1 thru #5 above.

Customization

It is expected that most organizations will implement their own custom Logger class in order to integrate ESAPI logging with their logging infrastructure. The ESAPI Reference Implementation is intended to provide a simple functional example of an implementation.

Configuration
There are various steps required to configure ESAPI for logging

A. Define the Log factory in the ESAPI.properties file (in your resources directory)
B. Define the Logger.* properties in ESAPI.properties

Use


The Log4JLogFactory reference implementation can be used in the following way:
//sample usage of ESAPI's Logger
Logger logger = ESAPI.getLogger("some Class or String");

logger.fatal(Logger.SECURITY_FAILURE, "some log message");
logger.debug(Logger.EVENT_FAILURE, "another log message");


Error Handling

Every application will eventually have to deal with an exception and it is vital that these are handled securely. If an attacker can force exceptions to occur and you fail to correctly handle these situations you will expose sensitive information about the inner workings of the application. These detailed error messages will help attackers build a picture of your application and fine tune their attacks.


EnterpriseSecurityException is the base class for all security related exceptions. You should pass in the root cause exception where possible. Constructors for classes extending EnterpriseSecurityException should be sure to call the appropriate super() method in order to ensure that logging and intrusion detection occur properly.


All EnterpriseSecurityExceptions have two messages, one for the user and one for the log file. This way, a message can be shown to the user that doesn't contain sensitive information or unnecessary implementation details. Meanwhile, all the critical information can be included in the exception so that it gets logged.


Note that the "logMessage" for ALL EnterpriseSecurityExceptions is logged in the log file. This feature should be used extensively throughout ESAPI implementations and the result is a fairly complete set of security log records. ALL EnterpriseSecurityExceptions are also sent to the IntrusionDetector for use in detecting anomolous patterns of application usage.


8. Data Protection

Data Protection은 컴퓨터 데이터의 오용 방지를 보장하는 프로세스이다.  ESAPI HTTPUtilities  인터페이스는 HTTP requests, responses, sessions, cookies, headers, and logging 에 대한 추가 보안을 제공하는 메소드들을 정의한다.


Prevent browser Caching

ESAPI.httpUtilities().setNoCacheHeaders(ESAPI.httpUtilities().getCurrentResponse());

 

중요한 데이터가 브라우저에 캐싱되는 것을 방지한다. 개발자는 이 메서드를 호출함으로써 중요데이터가  브라우저나 중간 프록시에 캐시되지 않도록 설정한다. 가장 안전한 방법은 가장 제한적인 설정으로 모든 관련 헤더를 설정하는 것이다.

 

다음과 같이 안전하게 헤더를 설정하도록 한다.
Cache-Control: no-store
Cache-Control: no-cache
Cache-Control: must-revalidate
Expires: -1



9. Http Security


HTTP Security는 HTTP requests, responses, sessions, cookies, headers, logging 보호를 의미한다.  ESAPI의 HTTPUtilities 인터페이스는 추가 보안을 제공하는 메서드를 정의하고 있다.

Unvalidated Redirects/Forwards

Web Application Redirects and Forwards은 사용자가 제공하는 파라미터를 목적지 URL로 사용하는 경우가 종종있다.  이런 경우 입력값에 대한 유효성 검사가 제대로 이루어지지 않는다면 공격자는 피싱또는 악성코드를 배포하는 사이트로 피해자를 보낼 수 있다. 

 ESAPI.httpUtilities().sendRedirect 는 리다이렉트에 대한 유효성을 검사하여 리다이렉트 취약점이 발생하지 않도록 한다.   ESAPI.httpUtilities().sendRedirect 는 애플리케이션의  WEB-INF 디렉토리하에 있는 리소스로만 리다이렉트를 허용한다.  유효성 검증작업은 ESAPI.properties 에서 Validation.Redirect 설정값으로 제어된다.




Posted by wychoi
,