Search This Blog

Tuesday, June 29, 2010

Optimize SQL Queries


Optimize SQL Queries
The reasons to optimize
Time is money and people don't like to wait so programs are expected to be fast.
In Internet time and client/server programming, it's even more true because suddenly a lot of people are waiting for the DB to give them an answer which makes response time even longer.
Theory of optimization
There are many ways to optimize Databases and queries. My method is the following.
Look at the DB Schema and see if it makes sense
Most often, Databases have bad designs and are not normalized. This can greatly affect the speed of your Database. As a general case, learn the 3 Normal Forms and apply them at all times(See Example: http://www.anaesthetist.com/mnm/sql/normal.htm). The normal forms above 3rd Normal Form are often called de-normalization forms but what this really means is that they break some rules to make the Database faster.
What I suggest is to stick to the 3rd normal form except if you are a DBA (which means you know subsequent forms and know what you're doing). Normalization after the 3rd NF is often done at a later time, not during design.
Only query what you really need
Filter as much as possible
Your Where Clause is the most important part for optimization.
 Select only the fields you need
Never use "Select *" -- Specify only the fields you need; it will be faster and will use less bandwidth.
Be careful with joins
Joins are expensive in terms of time. Make sure that you use all the keys that relate the two tables together and don't join to unused tables -- always try to join on indexed fields. The join type is important as well (INNER, OUTER,... ).
Optimize queries and stored procedures (Most Run First)
Queries are very fast. Generally, you can retrieve many records in less than a second, even with joins, sorting and calculations. As a rule of thumb, if your query is longer than a second, you can probably optimize it.
Start with the Queries that are most often used as well as the Queries that take the most time to execute.
Add, remove or modify indexes
If your query does Full Table Scans, indexes and proper filtering can solve what is normally a very time-consuming process. All primary keys need indexes because they make joins faster. This also means that all tables need a primary key. You can also add indexes on fields you often use for filtering in the Where Clauses.
You especially want to use Indexes on Integers, Booleans, and Numbers. On the other hand, you probably don't want to use indexes on Blobs, VarChars and Long Strings.
Be careful with adding indexes because they need to be maintained by the database. If you do many updates on that field, maintaining indexes might take more time than it saves.
In the Internet world, read-only tables are very common. When a table is read-only, you can add indexes with less negative impact because indexes don't need to be maintained (or only rarely need maintenance).
Move Queries to Stored Procedures (SP)
Stored Procedures are usually better and faster than queries for the following reasons:
   1. Stored Procedures are compiled (SQL Code is not), making them faster than SQL code.
   2. SPs don't use as much bandwidth because you can do many queries in one SP. SPs also stay on the server until the final results are returned.
   3. Stored Procedures are run on the server, which is typically faster.
   4. Calculations in code (VB, Java, C++, ...) are not as fast as SP in most cases.
   5. It keeps your DB access code separate from your presentation layer, which makes it easier to maintain (3 tiers model).
Remove unneeded Views
Views are a special type of Query -- they are not tables. They are logical and not physical so every time you run select * from MyView, you run the query that makes the view and your query on the view.
If you always need the same information, views could be good.
If you have to filter the View, it's like running a query on a query -- it's slower.

Tune DB settings
You can tune the DB in many ways. Update statistics used by the optimizer, run optimization options, make the DB read-only, etc... That takes a broader knowledge of the DB you work with and is mostly done by the DBA.
Using Query Analyses
In many Databases, there is a tool for running and optimizing queries. SQL Server has a tool called the Query Analyser, which is very useful for optimizing. You can write queries, execute them and, more importantly, see the execution plan. You use the execution to understand what SQL Server does with your query.
Optimization in Practice
Example 1:
I want to retrieve the name and salary of the employees of the R&D department.
Original:
Query: Select * From Employees
In Program: Add a filter on Dept or use command: if Dept = R&D--
Corrected:
Select Name, Salary From Employees Where Dept = ‘R&D’
In the corrected version, the DB filters data because it filters faster than the program.
Also, you only need the Name and Salary, so only ask for that.
The data that travels on the network will be much smaller, and therefore your performances will improve.
Example 2 (Sorting):
Original:
Select Name, Salary From Employees Where Dept = 'R&D' Order By Salary
Do you need that Order By Clause? Often, people use Order By in development to make sure returned data are ok; remove it if you don't need it.
If you need to sort the data, do it in the query, not in the program.


Example 3:
Original:
For i = 1 to 2000
Call Query: Select salary From Employees Where EmpID = Parameter(i)
Corrected:
Select salary From Employees Where EmpID >= 1 and EmpID <= 2000
The original Query involves a lot of network bandwidth and will make your whole system slow.
You should do as much as possible in the Query or Stored Procedure. Going back and forth is plain stupid.
Although this example seems simple, there are more complex examples on that theme.
Sometimes, the processing is so great that you think it's better to do it in the code but it's probably not.
Sometimes, your Stored Procedure will be better off creating a temporary table, inserting data in it and returning it than going back and forth 10,000 times. You might have a slower query that saves time on a greater number of records or that saves bandwidth.
Example 4 (Weak Joins):
You have two tables Orders and Customers. Customers can have many orders.
Original:
Select O.ItemPrice, C.Name From Orders O, Customers C
Corrected:
Select O.ItemPrice, C.Name From Orders O, Customers C Where O.CustomerID = C.CustomerID
In that case, the join was not there at all or was not there on all keys. That would return so many records that your query might take hours. It's a common mistake for beginners.
Corrected 2:
Depending on the DB you use, you will need to specify the Join type you want in different ways.
In SQL Server, the query would need to be corrected to:
Select O.ItemPrice, C.Name From Orders O INNER JOIN Customers C ON O.CustomerID = C.CustomerID
Choose the good join type (INNER, OUTER, LEFT, ...).
Note that in SQL Server, Microsoft suggests you use the joins like in the Corrected 2 instead of the joins in the Where Clause because it will be more optimized.

Example 5 (Weak Filters):
This is a more complicated example, but it illustrates filtering at its best.
We have two tables -- Products (ProductID, DescID, Price) and Description(DescID, LanguageID, Text). There are 100,000 Products and unfortunately we need them all.
There are 100 languages (LangID = 1 = English). We only want the English descriptions for the products.
We are expecting 100 000 Products (ProductName, Price).
First try:
Select D.Text As ProductName, P.Price From Products P INNER JOIN Description D On P.DescID = D.DescID Where D.LangID = 1
That works but it will be really slow because your DB needs to match 100,000 records with 10,000,000 records and then filter that Where LangID = 1.
The solution is to filter On LangID = 1 before joining the tables.
Corrected:
Select D.Text As ProductName, P.Price From (Select DescID, Text From Description Where D.LangID = 1) D INNER JOIN Products P On D.DescID = P.DescID
Now, that will be much faster. You should also make that query a Stored Procedure to make it faster.

Example 6 (Views):
Create View v_Employees AS Select * From Employees
Select * From v_Employees
This is just like running Select * From Employees twice.
You should not use the view in that case.
If you were to always use the data for employees of R&D and would not like to give the rights to everyone on that table because of salaries being confidential, you could use a view like that:
Create View v_R&DEmployees AS
Select Name, Salary From Employees Where Dept = 1 (Dept 1 is R&D).
You would then give the rights to View v_R&DEmployees to some people and would restrict the rights to Employees table to the DBA only.
That would be a possibly good use of views.


Tuesday, June 22, 2010

Validate User Credentials

Guessing User Credentials:-

When we submit wrong credentials, we receive a message that states that either the username is present on the system or the provided password is wrong. The information obtained can be used by an attacker to gain a list of users on system. This information can be used to attack the web application, for example, through a brute force or default username/password attack.


Technical Tips:-

Application should answer in the same manner for every failed attempt of authentication.

For Example:

Credentials submitted are not valid..
Or
UserName or Password mismatched..

EXTRA – TIPS:-
We can force to create user credentials in the following composition or a variance of such:
• at least: 1 uppercase character (A-Z)
• at least: 1 lowercase character (a-z)
• at least: 1 digit (0-9)
• at least one special character (!"£$%&...)
• a defined minimum length (e.g. 8 chars)
• a defined maximum length (as with all external input)
• no contiguous characters (e.g. 123abcd)
• not more than 2 identical characters in a row (1111)

CODE:-


/*
* 1. paste this basicValidate() in <SCRIPT></SCRIPT>
* 2. before submit() call this method
*
*/





//login.jsp
//**************************************************************************************************************************
<script type="text/javascript" src="js/sha.js"></script>
<script type="text/javascript" src="js/validations.js"></script>
<script language="javascript">

function calcHash()
{
//do salted hash code here..
}

function validate()
{
//var specialChars = "#,+,~,\`,=,\,,.,@,!,~,*,^,\`,&,$,(,),[,],{,},:,;,>,<,%,?,<,>,\",\'";
document.getElementById( "errors" ).innerHTML = '';
if ( trim(document.getElementById("uName").value) == "" || trim(document.getElementById("passwd").value) == "" )
{
document.getElementById( "errors" ).innerHTML = "Login / Password is not empty...";
return false;
}
if( ( !isValidAlphaNumericInput( document.getElementById("uName").value, "" ) ) || ( !isValidAlphaNumericInput( document.getElementById("passwd").value, "" ) ) ) //specialChars ) ) )
{
document.getElementById( "errors" ).innerHTML = "Login / Password is not an Alpha Numeric...";
return false;
}
/* validation for blankspace of userid
else if( isBlankSpace( trim(document.getElementById("uName").value) ) )
{
document.getElementById( "errors" ).innerHTML = "User Name is not be a blank space..";
return false;
}*/
else
{
//newHMAC();
calcHash();
}
}


</script>

<body>
<form action="login?action=login" name="frm" focus='uName'
method="post" autocomplete="off"><br />

UserName: <input type="text" name="uName" id="uName" styleClass="dropdown" size="30" /> <br />

Password :<input type="password" name="passwd" id="passwd" styleClass="dropdown" size="30" /> <br />

<input type="submit" value="Login" onclick="return validate()" />
<input type="reset" />
</form>

Monday, June 21, 2010

OWASP - Improper Error Handling DAO

Every piece of information an attacker receives about a targeted system or application is a valuable weapon. It is the job of application designers and programmers to keep these weapons from the hands of the enemy. Unfortunately, many Web applications cannot handle errors and, as a result, improper error handling occurs.
Because they contain valuable debugging information, error messages are intended for those who figure out and fix problems. Trouble arises when end users see these messages and use the information to solicit an attack. Here are four ways error messages can create security problems:
1. Many default messages divulge basic information about a system. This information, which may be presented as part of the message or inferred from the format, aids the attacker in selecting which techniques and exploits will help him gain access.
2. Attackers can use error messages to extract specific information from a system.
Example 1: If an attacker attempts to break in by brute force, error messages that include specifics, such as "invalid user name" or "invalid password" are more valuable than if they received a generic message, such as "Login incorrect."
Example 2: Attackers can determine which directories or files exist on a given Web server if it distinguishes between "directory or file not found" and "you are not authorized to see this directory or file." To prevent this, redirect them to the homepage, which will confound some automated attack tools.
Example 3: Errors that supply the full path name to executables, data files and other system assets help the attacker understand how things are laid out behind the firewall. In some cases, they reveal hosts of interest as well.
Example 4: Database errors can be especially helpful to attackers, providing them with host names of internal systems, as well as database, table and field names that can be used to craft SQL injection attacks.
3. Attackers can also use unexpected errors to knock an application off line, creating a denial-of-service attack. These attacks are created by taking advantage of error conditions that consume system resources, such as CPU and disk.
4. In a worst-case scenario, unexpected errors can provide an attacker with a buffer or stack overflow condition that sets the stage for an arbitrary code execution.
TIPS:-
So, what is a programmer to do? Do not rely on the operating system, server, database or other underlying packages to provide error handling. All errors should be handled by code the programmer writes. A well-designed application should include handlers for anticipated error conditions and a failsafe error handler for unanticipated conditions.
Error handlers should capture relevant, detailed information in a secure log for future analysis and present users with a generic error message that does not contain sensitive information. When designing the log file, keep security in mind. It should capture information such as user identifiers, IP addresses, dates and times for pattern analysis.
Having an error log is not enough, however. Someone will need to look at the log and analyze its contents. Many application-level reconnaissance and attacks can be detected by looking for patterns in log files. If a log file shows many error conditions falling through to the default exception handler, it may be time to update the error-handling code to deal with other conditions.
These best practices require the application designer and programmer to think like an attacker. When designing an error message, stop and think about whether it is presenting information the user shouldn't see or that an attacker could use.
Owners of Internet-based services and businesses are at war with those who seek to attack their applications -- don't give them additional information and weapons by saving a little time on error handling!

while (DoSomething()) {
try {
/* perform main loop here */
}
catch (Exception &e){
/* do nothing, but catch so it'll compile... */

//ERROR can log into AUDIT TRAIL with Type : ERROR

}
}





<!--
1. add this tags in web.xml
2. create "error.jsp" like below
3. add the audittrail statement in all your catch {} block like below
-->


<error-page>
<error-code>500</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<error-code>400</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<error-code>401</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<error-code>402</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error.jsp</location>
</error-page>
<error-page>
<exception-type>javax.faces.FacesException</exception-type>
<location>/error.jsp</location>
</error-page>
<error-page>
<exception-type>java.io.EOFException</exception-type>
<location>/error.jsp</location>
</error-page>




//error.jsp [you can design your custom error page]
//*********************************************************************************************

Error Contact Administrator
<a href="./homeOrindex.jsp">Home</a> <!-- the page should be redirect to your home or index page according to your decision -->



//catch {} block general format
//*********************************************************************************************

DOAuditTrail doaudittrail = new DOAuditTrail("userId here", "ipAddress here", "ERROR" , "description here"), "status here", "session id here" );
PDOAuditTrail.auditTrailDAO(doaudittrail);

//when ever you need to view this details, create a view and make a select query and display

Friday, June 18, 2010

Sanitization - OWASP


Sanitize with Whitelist

Any characters which are not part of an approved list can be removed, encoded or replaced.
 
The most common web application security weakness is the failure to properly validate input from the client or environment. This weakness leads to almost all of the major vulnerabilities in applications, such as Interpreter Injection, locale/Unicode attacks, file system attacks and buffer overflows. Data from the client should never be trusted for the client has every possibility to tamper with the data.

In many cases, Encoding has the potential to defuse attacks that rely on lack of input validation.
For example:-
If you use HTML entity encoding on user input before it is sent to a browser, it will prevent most XSS attacks. However, simply preventing attacks is not enough - you must perform Intrusion Detection in your applications. Otherwise, you are allowing attackers to repeatedly attack your application until they find a vulnerability that you haven't protected against. Detecting attempts to find these weaknesses is a critical protection mechanism.

Accept known good

This strategy is also known as "whitelist" or "positive" validation. The idea is that you should check that the data is one of a set of tightly constrained known good values. Any data that doesn't match should be rejected. Data should be:
  • Strongly typed at all times
  • Length checked and fields length minimized
  • Range checked if a numeric
  • Unsigned unless required to be signed
  • Syntax or grammar should be checked prior to first use or inspection
If you expect a postcode, validate for a postcode (type, length and syntax):

public String isPostcode(String postcode) {
    return (postcode != null && Pattern.matches("^(((2|8|9)\d{2})|((02|08|09)\d{2})|([1-9]\d{3}))$", postcode)) ? postcode : "";
}

Coding guidelines should use some form of visible tainting on input from the client or untrusted sources, such as third party connectors to make it obvious that the input is unsafe:

 
String taintPostcode = request.getParameter("postcode");
ValidationEngine validator = new ValidationEngine();
boolean isValidPostcode = validator.isPostcode(taintPostcode);


Reject known bad

This strategy, also known as "negative" or "blacklist" validation is a weak alternative to positive validation. Essentially, if you don't expect to see characters such as %3f or JavaScript or similar, reject strings containing them. This is a dangerous strategy, because the set of possible bad data is potentially infinite. Adopting this strategy means that you will have to maintain the list of "known bad" characters and patterns forever, and you will by definition have incomplete protection.
 
public String removeJavascript(String input) 
{
Pattern p = Pattern.compile("javascript", CASE_INSENSITIVE);
p.matcher(input);
return (!p.matches()) ? input : '';
}

It can take upwards of 90 regular expressions (see the CSS Cheat Sheet in the Development Guide 2.0) to eliminate known malicious software, and each regex needs to be run over every field. Obviously, this is slow and not secure. Just rejecting "current known bad" (which is at the time of writing hundreds of strings and literally millions of combinations) is insufficient if the input is a string. This strategy is directly akin to anti-virus pattern updates. Unless the business will allow updating "bad" regexes on a daily basis and support someone to research new attacks regularly, this approach will be obviated before long.


SANITIZE


public static String [] sanitizedData ( String... input )
{
String sanitizedData[] = new String[input.length];
int index = 0;

for ( String i : input )
{
sanitizedData[index++] = i.replaceAll ( "[\'~!@#$%^&*()\";: <>?/,.]", "’" );
}
return sanitizedData;
}


public static String [] sanitizedDatawithQuote ( String... input )
{
String sanitizedData[] = new String[input.length];
int index = 0;

for ( String i : input )
{
i = i.replaceAll ( "<", "<" );
i = i.replaceAll ( ">", ">" );
//etc..
sanitizedData[index] = i;

}
return sanitizedData;
}



//calling example

 
/*
String sanitizedData[] = SecureAlgorithm.sanitizedData ( "vijay\'~ !@#$%^&*()\";:<>?/,.", "jessy%" );
String sanitizedDatawithQuote[] = SecureAlgorithm.sanitizedDatawithQuote ( "vijay<>" );
System.out.println ( sanitizedData[0] + "\n" + sanitizedData[1] );
System.out.println ( sanitizedDatawithQuote[0] );

String taintPostcode = request.getParameter("postcode");
ValidationEngine validator = new ValidationEngine();
boolean isValidPostcode = validator.isPostcode(taintPostcode);
*/

Wednesday, June 16, 2010

OWASP CSRF - Cross-Site Request Forgery

Cross-Site Request Forgery (CSRF) is an attack that tricks the victim into loading a page that contains a malicious request. It is malicious in the sense that it inherits the identity and privileges of the victim to perform an undesired function on the victim's behalf, like change the victim's e-mail address, home address, or password, or purchase something. CSRF attacks generally target functions that cause a state change on the server but can also be used to access sensitive data

Sometimes, it is possible to store the CSRF attack on the vulnerable site itself. Such vulnerabilities are called Stored CSRF flaws. This can be accomplished by simply storing an IMG or IFRAME tag in a field that accepts HTML, or by a more complex cross-site scripting attack.

How does the attack work?

There are numerous ways in which an end-user can be tricked into loading information from or submitting information to a web application. In order to execute an attack, we must first understand how to generate a malicious request for our victim to execute. Let us consider the following example: Alice wishes to transfer $100 to Bob using bank.com. The request generated by Alice will look similar to the following:
POST http://bank.com/transfer.do HTTP/1.1
...
...
...
Content-Length: 19;
However, Maria notices that the same web application will execute the same transfer using URL parameters as follows: 
GET http://bank.com/transfer.do?acct=BOB&amount=100 HTTP/1.1 

Maria now decides to exploit this web application vulnerability using Alice as her victim. Maria first constructs the following URL which will transfer $100,000 from Alice's account to her account:
http://bank.com/transfer.do?acct=MARIA&amount=100000
Now that her malicious request is generated, Maria must trick Alice into submitting the request. The most basic method is to send Alice an HTML email containing the following: 

<a href="http://bank.com/transfer.do?acct=MARIA&amount=100000">View my Pictures! 

View my Pictures! 


Assuming Alice is authenticated with the application when she clicks the link, the transfer of $100,000 to Maria's account will occur. However, Maria realizes that if Alice clicks the link, then Alice will notice that a transfer has occurred. Therefore, Maria decides to hide the attack in a zero-byte image:

<img border="0" height="1" src="http://bank.com/transfer.do?acct=MARIA&amount=100000" width="1" />



If this image tag were included in the email, Alice would only see a little box indicating that the browser could not render the image. However, the browser will still submit the request to bank.com without any visual indication that the transfer has taken place.


Prevention



Challenge-Response

Challenge-Response is another defense option for CSRF. The following are some examples of challenge-response options.
  • CAPTCHA
  • Re-Authentication (password)
  • One-time Token
While challenge-response is a very strong defense to CSRF (assuming proper implementation), it does impact user experience. For applications in need of high security, tokens (transparent) and challenge-response should be used on high risk functions.

Client/User Prevention

Since CSRF vulnerabilities are reportedly widespread, it is recommended to follow best practices to mitigate risk. Some mitigating include:
  • Logoff immediately after using a Web application
  • Do not allow your browser to save username/passwords, and do not allow sites to “remember” your login
  • Do not use the same browser to access sensitive applications and to surf the Internet freely (tabbed browsing).
Integrated HTML-enabled mail/browser and newsreader/browser environments pose additional risks since simply viewing a mail message or a news message might lead to the execution of an attack.
 

Double Submit Cookies

Double submitting cookies is defined as sending the session ID cookie in two different ways for every form request. First as a traditional header value, and again as a hidden form value. When a user visits a site, the site should generate a (cryptographically strong) pseudorandom value and set it as a cookie on the user's machine. This is typically referred to as the session ID. The site should require every form submission to include this pseudorandom value as a hidden form value and also as a cookie value. When a POST request is sent to the site, the request should only be considered valid if the form value and the cookie value are the same. When an attacker submits a form on behalf of a user, he can only modify the values of the form. An attacker cannot read any data sent from the server or modify cookie values, per the same-origin policy. This means that while an attacker can send any value he wants with the form, the attacker will be unable to modify or read the value stored in the cookie. Since the cookie value and the form value must be the same, the attacker will be unable to successfully submit a form unless he is able to guess the session ID value.

While this approach is effective in mitigating the risk of cross-site request forgery, including authenticated session identifiers in HTTP parameters may increase the overall risk of session hijacking. Architects and developers must ensure that no network appliances or custom application code or modules explicitly log or otherwise disclose HTTP POST parameters. An attacker that is able to obtain access to repositories or channels that leak HTTP POST parameters will be able to replay the tokens and perform session hijacking attacks. Note, however, that transparently logging all HTTP POST parameters is a rare occurrence across network systems and web applications as doing so will expose significant sensitive data aside from session identifiers including passwords, credit card numbers, and or social security numbers. Inclusion of the session identifier within HTML can also be leveraged by cross-site scripting attacks to bypass HTTPOnly protections. Most modern browsers prevent client-side script from accessing HTTPOnly cookies. However, this protection is lost if HTTPOnly session identifiers are placed within HTML as client-side script can easily traverse and extract the identifier from the DOM. Developers are still encouraged to implement the synchronizer token pattern as described in this article and implemented in OWASP CSRFGuard.



.Thanks to wiki...

Tuesday, June 15, 2010

Html Forms Autocomplete = OFF - OWASP

HTML forms are a key component to exchanging information between a user and the server.
browser feature of remembering what you entered in previous text form fields with the same name. So, for example, if the field is named name and you had entered several variants of your name in other fields named name, then autocompletion provides those options in a dropdown. This image shows autocompletion being used in a form field:


Generally autocompletion is a useful browser feature, but occasionally it can be harmful. If the form field contains information such as a credit card number that should be left stored on the user's hard drive then you should turn autocompletion off. You can turn it off by setting AUTOCOMPLETE to OFF:


<input autocomplete="off" name="oPassword" type="password" > 
TIPS:-
1. Confidential Information must be OFF.

SQL Injection or Insertion

A SQL injection attack consists of insertion or "injection" of a SQL query via the input data from the client to the application. A successful SQL injection exploit can read sensitive data from the database, modify database data (Insert/Update/Delete), execute administration operations on the database (such as shutdown the DBMS), recover the content of a given file present on the DBMS file system and in some cases issue commands to the operating system. SQL injection attacks are a type of injection attack, in which SQL commands are injected into data-plane input in order to effect the execution of predefined SQL commands.

Incorrectly filtered escape characters

This form of SQL injection occurs when user input is not filtered for escape characters and is then passed into an SQL statement. This results in the potential manipulation of the statements performed on the database by the end user of the application.

The following line of code illustrates this vulnerability:
statement = "SELECT * FROM users WHERE name = '" + userName + "';"
This SQL code is designed to pull up the records of the specified username from its table of users. However, if the "userName" variable is crafted in a specific way by a malicious user, the SQL statement may do more than the code author intended. For example, setting the "userName" variable as
' or '1'='1
renders this SQL statement by the parent language:
SELECT * FROM users WHERE name = '' OR '1'='1';

 

 

Preventing SQL injection

~~~~~~~~~~~~~~~~~~~~~~~~~

Parameterized statements

With most development platforms, parameterized statements can be used that work with parameters (sometimes called placeholders or bind variables) instead of embedding user input in the statement. In many cases, the SQL statement is fixed, and each parameter is a scalar, not a table. The user input is then assigned (bound) to a parameter. This is an example using Java and the JDBC API:

PreparedStatement prep = conn.prepareStatement("SELECT * FROM USERS WHERE USERNAME=? AND PASSWORD=?");
prep.setString(1, username);
prep.setString(2, password);
prep.executeQuery();

Enforcement at the database level

Currently only the H2 Database Engine supports the ability to enforce query parameterization.However, one drawback is that query by example may not be possible or practical because it's difficult to implement query by example using parametrized queries.

Enforcement at the coding level

Using object-relational mapping libraries avoids the need to write SQL code. The ORM library in effect will generate parameterized SQL statements from object-oriented code.

Escaping

A straight-forward, though error-prone, way to prevent injections is to escape characters that have a special meaning in SQL. The manual for an SQL DBMS explains which characters have a special meaning, which allows creating a comprehensive blacklist of characters that need translation. For instance, every occurrence of a single quote (') in a parameter must be replaced by two single quotes ('') to form a valid SQL string literal. In PHP, for example, it is usual to escape parameters using the function mysql_real_escape_string before sending the SQL query:

$query = sprintf("SELECT * FROM Users where UserName='%s' and Password='%s'",
                  mysql_real_escape_string($Username),
                  mysql_real_escape_string($Password));
mysql_query($query);
This is error prone because it is easy to forget to escape a given string.

TIPS:-
1. Sanitize or Escape special characters
2. Bind or PreparedStatement
3. Check Length and type

Sunday, June 13, 2010

Security Audit Stages

There are two stages of Security Audit.
                                                Stage 1. Automation Auditing
                                                Stage 2. Manual Auditing

Automation Tools:-

        1. AppScan
        2. Scando
        3. Acunetix
        etc..

Manual Testing Tools:-

     1. Burp Suite
    2. IE Tamper
    3. Achilles
    etc..


How to prevent via coding ?   [Project should implement the following points]:-


Auto Completion for important controls like password
Salted hash for password fields
Sanitization to all the input controls
Browser Refresh [use captcha]
Steal Password via Refresh or back button [use redirection, clear cache]
Session Fixation [ use new session id before/after login ]
Brute Force [use captcha]
Guessing UserID
Always clear Browser cache
Insecure direct object reference  [ in search result screens, avoid give action link with pk id ]
CSRF
Downloading Secure File [ dont take a path from parameter ]
Inproper Error Handling [use proper tr{} catch{}, move to custom error page]
XSS [use sanitization, check server side validation (type,size,input data) ]
SQL Injection [use sanitization]
Cross Account Access
Privileged Escalation
Login Trail
Audit Trail
Forgot Password [use security question, captcha, send a mail link to change password (one time link) ]
etc..

Stealing Password via Browser Refresh - OWASP

The browser’s back and refresh features can be used to steal passwords from
insecurely written applications.

Browsers have the ability to maintain a recent record of pages that were visited
by a user. The back and forward button on browsers use this functionality to
display the pages recently browsed. In addition browsers also keep track of
variables that were POSTed to the server while fetching the page.

Problem if you code like this


Solve



TIPS:-
1. Redirect
2. Clear Browser Cache [safer case]

vijay.dr
9842088860

Wednesday, June 9, 2010

Salted Hash Password - OWASP

In very many - not to say almost all - Web applications user data is administered, from Web forum to Web shop. These user data encompass login information of the users which contain the password besides the user name - and this in plain text. A security leak par excellence.

Why is storing the user name and password in plain text a security leak?
Well, imagine a cracker gaining system access through eventual OS or server software errors, and being able to read the user database. As he now knows the user name and password of any arbitrary user he can now log on as a 'real' user and do whatever he wants with the permissions for that user - from ordering in the Web shop to character assassination on the forum. And you are the operator...

How can this security risk be eliminated?
Why should we roam far when a proven method for safe storage of passwords exists since decades: under UNIX, user passwords are stored as so called 'salted hashes'.

What is a Salted Hash?

A hash is a numerical value of fixed length which unequivocally identifies files of arbitrary legth. An example of a hashing algorithm is SHA1, which already figured as the topic of an ASP article (German). The reader might now say that saving the password as a hash would be sufficient, but why is this wrong?

The reason for this is that usually so called 'Dictionary Attacks' are run against hashed passwords - a good example being the MD5 hashed passwords of NT4. This is a Brute Force attack: all entries in a dictionary were hashed using MD5 and those hash values then are compared against the password database. Have a guess how quickly some passwords are found this way.

The intention behind a Salted Hash is to have this type of attack fail by attaching a random value - the so called salt - to each password and only then compute the hash over password and salt. For comparison of the password the salt has to be stored alongside the salted hash, but the only vector of attack is to re-code the dictionary for each individually stored password with the salt - and this takes quite a long time.


Storing the Salted Hash

As previously mentioned, we now need to store three fields instead of user name and password: user name, salt and the salted hash of the password. I also mentioned that when these data get into the hands of a cracker he will have a problem using standard attacks and most probably will look for an easier victim.

One point however must be kept in mind: it is now impossible to send a 'password reminder' email - all that can be done is to generate and send a new password for the user. As a number of mistakes is made in this field, we will begin with the .NET code for generating a truly random password.

Example - Java
**************

SecureAlgorithm.java

package com.product.common;

/**
* @author vijaydr
*/

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

public class SecureAlgorithm
{
public static String generateRandom () throws Exception
{
SecureRandom sr = SecureRandom.getInstance ( "SHA1PRNG" );
//System.out.println ( "SecureRandom : " + sr.nextInt () ); //if you enable then output return in negative
return String.valueOf ( Math.abs ( sr.nextInt () ) );
}

public static String [] sanitizedData ( String... input )
{
String sanitizedData[] = new String[input.length];
int index = 0;

for ( String i : input )
{
sanitizedData[index++] = i.replaceAll ( "[\'~!@#$%^&*()\";: <>?/,.]", "’" );
}
return sanitizedData;
}

private static String convertToHex ( byte [] data )
{
StringBuffer buf = new StringBuffer ();
for ( int i = 0; i < data.length; i++ ) { int halfbyte = ( data[i] >>> 4 ) & 0x0F;
int two_halfs = 0;
do
{
if ( ( 0 <= halfbyte ) && ( halfbyte <= 9 ) ) buf.append ( (char) ( '0' + halfbyte ) ); else buf.append ( (char) ( 'a' + ( halfbyte - 10 ) ) ); halfbyte = data[i] & 0x0F; } while ( two_halfs++ < 1 ); } return buf.toString (); } public static String SHA1 ( String text ) throws NoSuchAlgorithmException, UnsupportedEncodingException { MessageDigest md; md = MessageDigest.getInstance ( "SHA-1" ); byte [] sha1hash = new byte[40]; md.update ( text.getBytes ( "iso-8859-1" ), 0, text.length () ); sha1hash = md.digest (); return convertToHex ( sha1hash ); } public static void main ( String args[] ) { String sanitizedData[] = SecureAlgorithm.sanitizedData ( "vijay\'~ !@#$%^&*()\";:<>?/,.", "jessy%" );
System.out.println ( sanitizedData[0] + "\n" + sanitizedData[1] );
}

}

autoGenRandom.jsp

<%@page import="com.abi.searchEngine.ProductConstants"%>
<%
String autoGen = com.product.common.SecureAlgorithm.generateRandom();
session.setAttribute ( ProductConstants.ATTRIBE_AUTO_GEN_NUMBER, autoGen );
%>


index.jsp

<%@ page language="java" pageEncoding="ISO-8859-1"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1" />
<META Http-Equiv="Cache-Control" Content="no-cache"/>
<META Http-Equiv="Cache-Control" Content="no-store"/>
<META Http-Equiv="Pragma" Content="no-cache"/>
<META Http-Equiv="Expires" Content="0"/>

<%
response.setHeader ( "Cache-Control", "no-cache" );
response.setHeader ( "Pragma", "no-cache" );
response.setDateHeader ( "Expires", 0 );
response.setHeader ( "Cache-Control", "no-store" );
%>

<%@include file="autoGenRandom.jsp"%>

<title>Secure Engine</title>
<script type="text/javascript" src="js/sha.js"></script>
<script type="text/javascript" src="js/validations.js"></script>
<script type="text/javascript">

var autoGen = "<%=session.getAttribute ( ProductConstants.ATTRIBE_AUTO_GEN_NUMBER ).toString()%>";

var hashObj;
var hmacObj;
function calcHash()
{
var isSuccess = true;
var saltValue = "";
hashObj = new jsSHA(document.getElementById("passwd").value, "ASCII");
try {
saltValue = hashObj.getHash("SHA-1", "HEX");
} catch(e) {
isSuccess = false;
}

hashObj = new jsSHA(saltValue + autoGen, "ASCII");
try {
saltValue = hashObj.getHash("SHA-1", "HEX");
//alert ( saltValue );
} catch(e) {
isSuccess = false;
}

document.getElementById("passwd").value = saltValue;
return isSuccess;

}

function newHMAC()
{
//SHA-1,SHA-256
//ASCII, HEX
var inputTypeSelectBox = document.getElementById("passwd");
hmacObj = new jsSHA(inputTypeSelectBox.value, "ASCII");
var keyTypeSelectBox = "ASCII";
var hashVariantSelectBox = "SHA-1";
var hmac = hmacObj.getHMAC( autoGen, keyTypeSelectBox, hashVariantSelectBox, "HEX" );
try {
document.getElementById("passwd").value = hmac;
alert ( hmac );
} catch(e){
}
}

function msg()
{
document.getElementById( "errors" ).innerHTML = '<%= (request.getAttribute("errors")==null)?"":request.getAttribute("errors")%>';
}

function validate()
{
//var specialChars = "#,+,~,\`,=,\,,.,@,!,~,*,^,\`,&,$,(,),[,],{,},:,;,>,<,%,?,<,>,\",\'";
document.getElementById( "errors" ).innerHTML = '';
if ( trim(document.getElementById("uName").value) == "" || trim(document.getElementById("passwd").value) == "" )
{
document.getElementById( "errors" ).innerHTML = "Login / Password is not empty...";
return false;
}
if( ( !isValidAlphaNumericInput( document.getElementById("uName").value, "" ) ) || ( !isValidAlphaNumericInput( document.getElementById("passwd").value, "" ) ) ) //specialChars ) ) )
{
document.getElementById( "errors" ).innerHTML = "Login / Password is not an Alpha Numeric...";
return false;
}
/* validation for blankspace of userid
else if( isBlankSpace( trim(document.getElementById("uName").value) ) )
{
document.getElementById( "errors" ).innerHTML = "User Name is not be a blank space..";
return false;
}*/
else
{
//newHMAC();
calcHash();
}
}


function noBack(){
window.history.forward()
}

noBack();
window.onload=noBack;
window.onpageshow=function(evt){if(evt.persisted)noBack()}
window.onunload=function(){void(0)}

</script>




<style type="text/css">
<!--
.style1 {
color: #666666
}

.style2 {
color: #333333;
font-size: 10pt;
}

.style3 {
font-family: Georgia, "Times New Roman", Times, serif;
font-size: 12px;
}
-->
</style>
</head>
<body onload="msg();">
<table width="60%" height="80%" border="0" align="center">
<tr height="30%">
<td colspan="2">  <img
src="jsp/includes/images/kpisoft_tm.jpg" /></td>
</tr>
<tr class="tableRow" align="center">
<td colspan="2">
<h3>Secure Engine<br />
</h3>
</td>
</tr>

<tr>
<td width="60%">
<p align="justify" class="style1 style3">Business and technology
solutions provider based in Bangalore with development centers in
Madurai and Chennai specializing in services to Small and Medium
Businesses and independent software vendors (ISVs). We deliver
reliable and high quality end-to-end solutions that significantly
enhance the competitiveness of our clients in addition to contributing
to productivity and profitability.</p>
<p align="justify" class="style1 style3"><br />
</p>
<p align="justify" class="style1 style3"><img
src="jsp/includes/images/support.jpg" /></p>
<p align="justify">Company adopts business unit approach towards
specializing in breadth and width of the IT offerings but would
provide its clientele with centralized engagement approach for their
various IT needs. <span class="style2">.</span> <br />
</p>
</td>
<td><br />

<form action="login?action=login" name="frm" focus='uName'
method="post" autocomplete="off"><br />
<table width="388" height="126" border="0">
<tr>
<!-- <th colspan="2" id="infoErrorMsg" width="211" height="31" scope="row">  -->
<th> </th>
<th colspan="2"><font id="errors" class="Mandatory" color="red"></font>
</th>
</tr>
<tr>
<th colspan="2" width="211" height="31" scope="row">
<div align="right">Login Name :</div>
</th>
<td width="161"><input type="text" name="uName" id="uName" styleClass="dropdown" size="30" /> <br />
</td>
</tr>
<tr>
<th colspan="2" height="32" scope="row">
<div align="right">Password   :</div>
</th>
<td><input type="password" name="passwd" id="passwd" styleClass="dropdown" size="30" /> <br />
</td>
</tr>
<tr>
<th colspan="2" height="53" scope="row"><br />
</th>
<td><br />
<div align="center">
<input type="submit" value="Login" onclick="return validate()" />
<input type="reset" /></div>
<br />
</td>
</tr>
</table>
<br />
<br />

</form>
</td>
</tr>
<tr height="50%">
<td colspan="2" align="right"><a href="<%=request.getContextPath()%>/fp.jsp">Forgot Password</a></td>
</tr>

</table>

<p align='center'><%@include file="footer.jsp"%></p>

</body>
</html>


LoginCheck.java

public void doPost ( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException
{
response.setContentType ( "text/html" );
PrintWriter out = response.getWriter ();
HttpSession session = request.getSession ();
String autoGen = session.getAttribute ( ProductConstants.ATTRIBE_AUTO_GEN_NUMBER ).toString ();
PreparedStatement st;
boolean success = false;
String nextJSP = "/index.jsp";
RequestDispatcher dispatcher = null;

try
{
if ( session.getAttribute ( ProductConstants.SESSION_USER ) == null )
{
String uName = request.getParameter ( "uName" );
String passwd = request.getParameter ( "passwd" );

uName = (SecureAlgorithm.sanitizedData ( uName ) )[0];

dbConnection = DBConnection.getDBConnection ();
String query = rb.getString ( "user.login" );
query += " and sha1(concat(pwd,'" + autoGen + "')) = ? ";
System.out.println ( "query " + query );

st = dbConnection.prepareStatement ( query );
st.setString ( 1, uName );
st.setString ( 2, passwd );

ResultSet rs = st.executeQuery ();
if ( rs.next () )
{
success = true;
Login login = new Login ();
login.setId ( rs.getInt ( "id" ) );
login.setLoginid ( uName );
login.setDeptId ( rs.getInt ("deptid") );
login.setUserDetailsId ( rs.getString ( "userid" ) );
CommonUtils.generateNewJSessionId ( request, false );
session = request.getSession ();
session.setAttribute ( ProductConstants.SESSION_USER, login );
CommonUtils.saveAuditLog ( dbConnection, new AuditLogger ( -1, String.valueOf ( login.getId () ), rb.getString ( "action.login.type" ), rb.getString ( "action.login.type.message" ), new Date (), ProductConstants.STATUS_SUCCESS ) );
}
else
{
CommonUtils.saveAuditLog ( dbConnection, new AuditLogger ( -1, uName, rb.getString ( "action.login.type" ), rb.getString ( "action.login.type.message" ), new Date (), ProductConstants.STATUS_FAILURE ) );
}
}
if ( success )
{
nextJSP = "redirect.jsp";
request.removeAttribute ( ProductConstants.ATTRIB_ERRORS );
// dispatcher = getServletContext ().getRequestDispatcher ( nextJSP );
// dispatcher.forward ( request, response );
response.sendRedirect ( nextJSP );
}
else
{
nextJSP = "/" + ProductConstants.URL_INDEX; // dispatcher call, so put /index.jsp instead index.jsp
request.setAttribute ( ProductConstants.ATTRIB_ERRORS, "Login error" );
dispatcher = getServletContext ().getRequestDispatcher ( nextJSP );
dispatcher.forward ( request, response );
// response.sendRedirect ( nextJSP );
}

}
catch ( Exception e )
{
System.out.println ( e );
}
finally
{
try
{
DBConnection.closeConnection ();

}
catch ( Exception e )
{
e.printStackTrace ();
}
}
}



ProductConstants

package com.abi.searchEngine;
public class ProductConstants
{
   public static String CONFIG_FILE = "myapp";
   public static String SESSION_USER = "login";
   public static String ATTRIB_ERRORS = "errors";

   //url
   public static String URL_INDEX = "index.jsp";
   public static String ATTRIBE_AUTO_GEN_NUMBER = "autoGen";

   public static String STATUS_SUCCESS = "SUCCESS";
   public static String STATUS_FAILURE = "FAILURE";
   public static String STATUS_ONGOING = "ONGOING";

   public static String ITEM_ID = "itemId";
   public static String ID = "id";

   public static String PURCHASE_LIST = "purchaseList";
   public static String PURCHASE = "purchase";
   public static int ADMIN_ID = 1;

   public static String TRUE = "t";
   public static String FALSE = "f";

   public static String EDIT_PURCHASE = "editPurchase";
   public static String LOGOUT = "lt";

}

//user.login=SELECT l.id, l.pwd, l.userid, d.id as deptid FROM login l JOIN userdetails ud ON ud.id = l.id JOIN department d ON d.id = ud.deptid WHERE loginid = ?

Monday, June 7, 2010

Session Fixation - OWASP

The session fixation attack is a class of Session Hijacking, which steals the established session between the client and the Web Server after the user logs in. Instead, the Session Fixation attack fixes an established session on the victim's browser, so the attack starts before the user logs in.
There are several techniques to execute the attack; it depends on how the Web application deals with session tokens. Below are some of the most common techniques:
• Session token in the URL argument: The Session ID is sent to the victim in a hyperlink and the victim accesses the site through the malicious URL.
• Session token in a hidden form field:In this method, the victim must be tricked to authenticate in the target Web Server, using a login form developed for the attacker. The form could be hosted in the evil web server or directly in html formatted e-mail.
• Session ID in a cookie:
o Client-side script
Most browsers support the execution of client-side scripting. In this case, the aggressor could use attacks of code injection as the XSS (Cross-site scripting) attack to insert a malicious code in the hyperlink sent to the victim and fix a Session ID in its cookie. Using the function document.cookie, the browser which executes the command becomes capable of fixing values inside of the cookie that it will use to keep a session between the client and the Web Application.
o tag
tag also is considered a code injection attack, however, different from the XSS attack where undesirable scripts can be disabled, or the execution can be denied. The attack using this method becomes much more efficient because it's impossible to disable the processing of these tags in the browsers.
o HTTP header response
This method explores the server response to fix the Session ID in the victim's browser. Including the parameter Set-Cookie in the HTTP header response, the attacker is able to insert the value of Session ID in the cookie and sends it to the victim's browser.

Example1




Example2

Client-side scripting

 http://website.kom/<script>document.cookie=”sessionid=abcd”;</script>

The processes for the attack using the execution of scripts in the victim's browser are very similar to example 1, however, in this case, the Session ID does not appear as an argument of the URL, but inside of the cookie. To fix the value of the Session ID in the victim's cookie, the attacker could insert a JavaScript code in the URL that will be executed in the victim's browser.
http://website.kom/

Example 3

<META> tag

As well as client-side scripting, the code injection must be made in the URL that will be sent to the victim.

http://website.kon/<meta http-equiv=Set-Cookie content=”sessionid=abcd”>

Example 4

HTTP header response
The insertion of the value of the SessionID into the cookie manipulating the server response can be made, intercepting the packages exchanged between the client and the Web Application inserting the Set-Cookie parameter.



How to Solve ?
************

1. when ever the client request a page [ generate a brand new session id]
2. once he input login credentials [ check and generate a new brand session id to track ]
3. once he logout his/her session [ make session.invalidate() and create a new session again ]


Note : adding Token is very good and more safer also..

by
http://drvijayy2k2.50webs.com/contact.html



OWASP secure Issues Handling

Hit Counter


View My Stats