我们再来讨论如何开发安全的web应用。网络上大部分资源都是开放,免费的。但是有些资源只需要特定的用户才能访问,例如一个论坛只有注册用户才能发言,管理员才能管理后台程序。为了让不同用户访问不同资源,就需要采用安全机制来保护web应用程序的资源,避免关键信息被未授权用户访问。
验证机制
在servlet规范中,定义了四种验证用户的机制。
HTTP Basic Authentication
Http基本验证是在HTTP 1.0中定义的、基于用户名和密码验证机制。当web浏览器请求受保护的资源时,web服务器会弹出一个对话框,让用户输入用户名和密码。web客户端从用户处得到用户名和密码,然后传给服务器。服务器负责验证,如果密码正确,服务器将发送用户所请求的资源。
HTTP Digest Authentication
和HTTP基本验证相似,HTTP摘要验证也是基于用户名和密码来验证用户的,不同的是,使用摘要验证,用户密码是以加密的形式(对密码采用MD5摘要算法)传输的,这比采用Base64编码要安全的多。
HTTP Client Authentication
HTTPS(Secure HTTP)是在SSL(Secure Socket Layer,安全套接字)之上的HTTP协议。SSL是1995年由网景公司提出的一种安全协议,用于浏览器套接字和服务器套接字之间建立一个安全的连接。SSL由两个子协议组成,一个用于建立安全的连接,一个使用安全的连接。当建立安全连接之后,通信双方使用同一个会话密钥对传输的信息进行加密。HTTPS客户端验证主要在电子商务应用程序中使用。
Form Baesd Authentication
基于表单的验证类似于基本验证。不同的是,基于表单的验证使用定制的HTML表单让用户输入用户名和密码,而不是使用浏览器的弹出对话框。
声明式安全
声明式安全是在web.xml文件中指定web应用程序的安全处理机制,这使得一个web应用程序无须修改任何源代码就可以获得安全性。默认情况下,web应用程序的所有资源对每个人都是开放访问的。通过在web.xml中配置<security-constraint>和<login-config>元素来限制对资源的访问。
<?xml version="1.0" encoding="ISO-8859-1"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" metadata-complete="true"> <!-- Define a Security Constraint on this Application --> <!-- NOTE: None of these roles are present in the default users file --> <security-constraint> <web-resource-collection> <web-resource-name>Protected Area</web-resource-name> <url-pattern>*.html</url-pattern> <url-pattern>*.jsp</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>admin</role-name> </auth-constraint> </security-constraint> <!-- Define the Login Configuration for this Application --> <login-config> <auth-method>BASIC</auth-method> <realm-name>Tomcat Manager Application</realm-name> </login-config> <!-- Security roles referenced by this web application --> <security-role> <role-name>admin</role-name> </security-role> <security-role> <role-name>manager</role-name> </security-role> </web-app>
如果在<web-resource-collection>元素下没有使用<url-pattern>元素,那意味着对所有的HTTP方法都要施加安全限制,如果使用了该元素,则只对指定的HTTP方法施加安全限制。
<auth-constraint>元素指定可以访问受保护资源的角色。<role-name>指定角色的名字,这二个名字必须是在<security-role>中指定的角色名,或者使用保留角色名“*”,表示web应用程序中所有角色。如果在 <auth-constraint>元素中没有指定<role-name>子元素,那么表示在任何情况下,没有任何用户可以访问受保护的资源,如果定义了<role-name>子元素,则其指定的用户可以访问受保护的资源。如果没有使用 <auth-constraint>元素,那么容器允许用户不经验证就访问受保护的资源。
<login-config>元素用于指定web应用程序使用的验证机制。<auth-method>元素配置web应用程序验证的机制,该元素的值必须是BASIC,DIGEST,FORM,CLIENT-CERT其中之一,或者是产品供应商指定的验证模式。除了FORM外,其他3种验证只需要在<auth-method>中配置即可。
程序式安全
在日常应用中,我们可能需要多个用户或者多个角色都有权限访问某个资源,这样更细粒度的安全控制,采用声明式安全无法做到。此时,我们可以在程序代码中进一步实现细粒度的安全控制。程序式安全由HttpServletRequest接口中定义的三个方法组成,如下所示:
Public String getRemoteUser() //如果用户已被验证,该方法返回用户的登录名。否则,返回null。 Public java.security.Principal getUserPrincipal() //返回一个Principal对象,该对象包含了当前已经验证的用户名,如果还没被验证,返回null。 Public boolean isUserInRole(String role) //判断已验证的用户角色是否属于指定角色,如果用户还没有被验证,返回null。
SQL注入攻击的防范
web应用程序的安全涉及多个方面,前面讲述的是通过验证和授权来防止未授权的用户访问受保护的资源。但有时候,安全问题往往是由系统本身的漏洞或程序员的疏忽引起的。例如,下面一段代码:
String name = request.getParameter("username"); String passwd = request.getParameter("password"); ... Statement stmt = conn.createStatement(); String sql = "select username from admins where username ="+ "'"+name+"' and password = '"+passwd+"'"; ResultSet rs = stmt.executeQuery(sql); while(rs.next()) { ... } ...
select username from admins where username ='shan' and password = '1234'
如果一个恶意用户通过查看网页源码,知道了表单中输入用户名的文本域和口令域的名字,直接在浏览器网址栏输入”http://www.test.com/login.jsp?username=abcd&password=1111 or '1'='1'“,于是就顺利的访问了管理页面。为什么随便一个用户名和密码就能访问呢?我们查看一下构造的sql语句就明白了。如下:
select username from admins where username ='shan' and password = '1234' or '1'='1'
最后的'1'='1'是恒等条件。所以这个恶意用户利用了sql语句的特点,构造了一个特殊查询,让原本不成立的语句就变得成立。这就是sql注入攻击的一个例子。
在java中,要防止上述情况的发生,只需要用PreparedStatement取代Statement即可。所以在实际应用中,要尽量使用PreparedStatement。
转载请注明出处:http://blog.csdn.net/iAm333