| CARVIEW |
|
webappsecurity
|
| Summary | Secure Servlet Filter to prevent application level attacks |
|---|---|
| Categories | None |
| License | Apache Software License |
| Owner(s) | ivarchan |
Message from the owner(s)
Ivar Chan
Table of Contents
WebAppSecurity is a web application filter framework that has security features that can prevent most application level attacks including fishing, overloading, and cracking. It is designed to prevent attacks that lie above http, such as WSDL and HTML. This article describes how to defend against a bruteforce password cracker attacking a website. The actual tests described below are located in conf/test/html/unit/simple-password-cracker. To run the website attack, run "ant". Inspect the output.log file to see the program trace.
To test an unsecure webapp, drop the demoapp-unsecure.war file into the webapps directory of your application server. Goto https://localhost:[port]/demoapp-unsecure and log into the account successfully with username "johndoe" and password "johndoe". Try again now with different username/passwords multiple times. The website should not reject you from the website.
Perform the same procedure as testing an unsecure webapp except drop the demoapp-secure.war file into the webapps dir and this time hit https://localhost:[port]/demoapp-unsecure. After three invalid username/password combinations, the filter will reject the client from the website. To retest, stop the webapp, modify the WEB-INF/acl.xml by removing the entry with your ip, and restart the webapp.
Docs are kinda light right now. Look and modify the security.xml file in the demo apps and inspect the output.log file (In Tomcat this will probably be under tomcat/bin). Email me, I'd like to see what type of rules I should include in an application level firewall.
- include the following in the web.xml file
<filter> <filter-name>InitFilter</filter-name> <filter-class> com.openinventions.webappfilter.InitServletFilter </filter-class> </filter> <filter> <filter-name>SecurityFilter</filter-name> <filter-class> com.openinventions.webappfilter.ServletFilter </filter-class> <init-param> <param-name>file</param-name> <param-value>WEB-INF/security.xml</param-value> </init-param> </filter> <filter> <filter-name>ResponseServletFilter</filter-name> <filter-class> com.openinventions.webappfilter.ResponseServletFilter </filter-class> </filter> <filter-mapping> <filter-name>InitFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>SecurityFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>ResponseServletFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> - ensure the following libraries are in WEB-INF/lib: commons-jxpath.jar, commons-logging.jar, jdom.jar, junit.jar, log4j-1.2.1.jar, metaframework.jar, webappsecurity.jar
- ensure security.xml is in the WEB-INF dir. Got questions about this file. Email me.
A web application requires security to prevent hackers from running brute force attacks on user accounts. To start off, a simple policy is required to ban an ip from accessing a website if it fails to log into an account after three tries.
Let's express the attack as a test case. First, let's have a legitimate user log into his account.
Successful Login
- Start Test
- Create client with ip 192.168.1.100 and hit localhost 8080
- Post a request to path /loginsubmit with username "johndoe" and password "johndoe"
- Check the response for "Welcome John Doe"
This is easy to read. However, it's a pain to parse. How about giving the test some structure using XML but still make it easy to read.
<test>
<name>Successful Login</name>
<client>
<host>localhost</host>
<port>8080</port>
<ip>192.168.1.100</ip>
<request action="post">
<path>/loginsubmit</path>
<param><name>username</name><value>johndoe</value></param>
<param><name>password</name><value>johndoe</value></param>
<response>
<assert>
<xpath>/res/body</xpath>
<regex>[\s\S]*Welcome John Doe[\s\S]*</regex>
</assert>
</response>
</request>
</client>
</test>
Now, let's express the attack.
Unsucessful Login
- Start Test
- Create client with ip 192.168.1.100 and hit localhost 8080
- Post a request to path /loginsubmit with username "johndoe" and password "hello"
- Check the response for "invalid username/password combination"
- Repeat 3-4 using password "hello1" and "hello2"
- Post a request to path /loginsubmit with username "johndoe" and password "hello3"
- Check the response for "rejected"
Structured as XML
<test>
<name>Unsuccessful login</name>
<client>
<host>localhost</host>
<port>8080</port>
<ip>192.168.1.100</ip>
<request>
<path>/loginsubmit</path>
<param><name>username</name><value>johndoe</value></param>
<param><name>password</name><value>hello</value></param>
<response>
<assert>
<xpath>/res/body</xpath>
<regex>[\s\S]*invalid username/password combination[\s\S]*</regex>
</assert>
</response>
</request>
<request>
<path>/loginsubmit</path>
<param><name>username</name><value>johndoe</value></param>
<param><name>password</name><value>hello1</value></param>
<response>
<assert>
<xpath>/res/body</xpath>
<regex>[\s\S]*invalid username/password combination[\s\S]*</regex>
</assert>
</response>
</request>
<request>
<path>/loginsubmit</path>
<param><name>username</name><value>johndoe</value></param>
<param><name>password</name><value>hello2</value></param>
<response>
<assert>
<xpath>/res/body</xpath>
<regex>[\s\S]*invalid username/password combination[\s\S]*</regex>
</assert>
</response>
</request>
<request>
<path>/loginsubmit</path>
<param><name>username</name><value>johndoe</value></param>
<param><name>password</name><value>hello3</value></param>
<response>
<assert>
<xpath>/res/body</xpath>
<regex>[\s\S]*rejected[\s\S]*</regex>
</assert>
</response>
</request>
</client>
</test>
A security filter will
- Inspect every request coming in. Reject all requests with banned IPs.
- Inspect every response going out. For a user that has received the "invalid username/password combination" page more than three times, reject his ip.
<reject>
<reject-denied/>
</reject>
<request>
<expr>
/filterDirection = "forward";
</expr>
</request>
<response>
<match>
<xpath>/res/body</xpath>
<regex>[\s\S]*invalid username/password combination[\s\S]*</regex>
<block>
<log>
<level>debug</level>
<section>/login</section>
<message>user entered invalid password.</message>
</log>
<expr>/invalidLogin = /invalidLogin + 1;</expr>
<if test="/invalidLogin > 2">
<banIP/>
<log>
<level>info</level>
<path>/login</path>
<message>$req/param[name='username']/value user banned.</message>
</log>
</if>
</block>
</match>
</response>
A website filter will return mocked webpages for testing purposes.
<request>
<request>
<match>
<xpath>/req/path</xpath><string></string>
<response>
<expr>
/res/body =
""
<html>
<body>
Welcome to the Test Password Cracking Website<p />
<a href="/webappsecurity/login">login</a>
</body>
</html>
"";
/filterDirection = "forward";
</expr>
</response>
</match>
</request>
<request>
<match>
<xpath>/req/path</xpath><string>/login</string>
<response>
<expr>
/res/body =
""
<html>
<body>
Enter username and password to login<p />
<form action="/webappsecurity/loginsubmit" method="post">
<input name="username"/><br />
<input name="password"/><br />
<input type="submit" value="submit"/>
</form>
</body>
</html>
"";
/filterDirection = "forward";
</expr>
</response>
</match>
</request>
<request>
<match>
<xpath>/req/path</xpath><string>/loginsubmit</string>
<response>
<match>
<xpath>/req/param[name='username']/value</xpath><string>johndoe</string>
<and/>
<xpath>/req/param[name='password']/value</xpath><string>johndoe</string>
<expr>
/res/body =
""
<html>
<body>
Welcome John Doe!
</body>
</html>
"";
/filterDirection = "forward";
</expr>
</match>
</response>
<response>
<expr>
/res/body =
""
<html>
<body>
invalid username/password combination. Please try again.<p />
<form action="/webappsecurity/loginsubmit" method="post">
<input name="username"/><br />
<input name="password"/><br />
<input type="submit" value="submit"/>
</form>
</body>
</html>
"";
/filterDirection = "forward";
</expr>
</response>
</match>
</request>
</request>
| Powered by CollabNet | Feedback |
FAQ |
Press |
Developer tools
© 1995 - 2007 CollabNet. CollabNet is a registered trademark of CollabNet, Inc. |
