第十四章_安全性

14.1、验证和授权

验证是检验某个人是否是他/她所声称的那个人的过程。

Servlet/JSP应用程序中,验证通常是通过要求用户输入username和password来完毕的。

授权主要是确定一个用户具有什么样的訪问级别。

它使用于包括多个訪问区域的应用程序,使用户可以訪问应用程序的某一部分,可是不能訪问其它部分。

比如。网上商店可以分为公共区(供一般的公共浏览和查找商品),买家区(供已注冊用户下单用),以及须要最高訪问级别的管理区。不仅管理员用户自身也须要进行验证,而且还必须是已经被同意訪问管理区的用户才行。訪问级别常常被称作角色。

14.1.1、定义用户和角色

每一种兼容的Servlet/JSP容器都必须提供一种定义用户和角色的方法。假设你使用的是Tomcat,就能够通过编辑conf文件夹下的tomcat-users.xml文件来创建用户和角色。tomcat-users.xml文件范比例如以下:

<?xml version=’1.0’ encoding=’utf-8’?>

<tomcat-users>

<role rolename=”manager”/>

<role rolename=”member”/>

<user username=”tom” password=”secret” roles=”manager,member”/>

<user username=”jerry” password=”secret” roles=”member”/>

</tomcat-users>

tomcat-users.xml文件是一个带有tomcat-users根源素的XML文档。

当中有roleuser元素。

role元素定义角色。user元素定义用户。role元素有一个rolename属性,用来指定角色的名称。user元素有usernamepasswordroles属性。username属性指定用户名称,password属性指定密码,roles属性则指定该用户所属的一个或多个角色


14.1.2、强加安全性约束

前面讲过,将静态资源和JSP页面保存在WEB-INF或其下的某一个文件夹下。能够讲他们隐藏起来。

放在这里的资源无法直接通过输入网址而訪问到。可是仍然能够通过一个Servlet或者JSP页面跳转到那里。尽管这样的方法简单直接,但缺点是藏在这里的资源就永远被藏起来了。它们永远无法被直接訪问到。假设仅仅是想避免未授权的用户訪问这些资源,那么能够讲它们放在应用程序文件夹下的某一个文件夹中。并在部署描写叙述符中声明一个安全性约束。

security-constraint元素用于指定一个资源集合,以及能够訪问这些资源的一个或多个角色。这个元素能够有两个子元素:web-resource-collectionauth-constraint

web-resource-collection元素用于指定一个资源集合,而且能够带有下面元素:web-resource-namedescriptionurl-patternhttp-methodhttp-method-ommission

web-resource-collection元素能够带有多个url-pattern元素。每个子元素都表示所包括安全性约束实行的一种URL模式。我们能够在url-pattern元素中用一个星号(*)表示一种特定的资源类型(*.jsp)。或者表示某个文件夹下的全部资源(/*/jsp/*)。可是这两种不能合二为一,比方,无法表示某一个特定文件夹下的某一种特定的类型。因此,假设用/jsp/*.jsp表示jsp文件夹下的全部jsp页面,那么这个URL模式将是无效的。而是要用/jsp/*来表示。可是这样又限制了jsp文件夹下那些非jsp的页面。

http-method元素中定义了一个HTTP方法,包括的安全性约束即应用到该方法中。

比如,web-resource-collection元素带有一个GET http-method元素,表示web-resource-collection元素仅仅应用于HTTPget方法。包括资源集合的安全性约束并不能保护其它的HTTP方法。比如Post方法和Put方法。假设没有http-method元素,表示这个安全性约束将会限制对全部HTTP方法的訪问。同一个web-resource-collection元素中能够带有多个http-method元素。

http-method-omission元素指定的是不再所包括安全性约束中的HTTP方法。因此。指定<http-method-omission>GET</http-method-omission>限制了对除GET之外的全部HTTP方法的訪问。

http-methodhttp-method-omission元素不能同一时候出如今同一个web-resource-collection元素中。

部署描写叙述符中能够有多个security-constraint元素。假设安全性约束元素中没有auth-constraint元素。那么这个资源集合将不能受到保护。此外,假设你指定了一个没有在容器中定义的角色。那么将没有人能够直接訪问这个资源集合。可是,你还是能够通过一个Servlet或者JSP页面跳转到集合中的某个资源。

举个样例。

以下的web.xml文件里的security-constraint元素限制了对全部jsp页面的訪问。因为auth-constraint元素中没有包括role-name元素。因此不能通过url来訪问这些资源。

<?xml version="1.0" encoding="UTF-8"?

> <web-app version="3.0" 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"> <display-name></display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <security-constraint> <web-resource-collection> <web-resource-name>JSP pages</web-resource-name> <!-- 全部的jsp页面都不能被訪问 --> <url-pattern>*.jsp</url-pattern> </web-resource-collection> <auth-constraint></auth-constraint> </security-constraint> </web-app>


如今,能够在浏览器中打开网址測试一下:

Servlet容器会发送一条HTTP403错误,温和地告诉你:Access to the requested resource has been denied(禁止訪问)。


14.2、验证方法

学会怎样对一个资源集合强加安全性约束之后,还应该知道怎样对訪问这些资源的用户进行验证。对于声明式保护的资源,能够在部署描写叙述符中使用security-constraint元素,通过使用HTTP 1.1提供的解决方式来完毕验证:基本訪问验证和摘要訪问验证。

此外,也能够使用基于表单的訪问验证。

14.2.1、基本訪问验证

基本訪问验证,简称基本验证,是一种接受username和password的HTTP验证。在基本訪问验证中,假设用户訪问受保护的资源,将会遭到server的拒绝,并返回一个401(未授权)响应。该响应中包括一个WWW-Authenticate标头,当中至少包括一个适用于被请求资源的角色,比如:

HTTP/1.1 401 Authorization Required

Server: Apache-Coyote/1.1

Date: Wed, 21 Dec 2011 11:32:09 GMT

WWW-Authenticate: Basic realm=”Members Only”

随后浏览器屏幕上回显示一个登录对话框。供用户输入username和password。

当用户单击Login登录button时,username后面会被添上一个冒号,并和password结合在一起。这个字符串被送到server之前,将先用Base64算法进行编码。登录成功之后。server就会发出被请求的资源。

Base64是一种非常弱的算法,因此Base64消息非常easy被破解。

因此。要考虑使用摘要訪问来取代。

以下展示了怎样使用基本訪问验证。第一个security-constraint元素是避免JSP页面被直接訪问。第二个是限制仅仅有managermember角色的用户才干訪问Servlet1 Servlet

Servlet1类是一个跳转到1.jsp页面的简单Servlet

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
	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">
  <display-name></display-name>	
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  <security-constraint>
  	<web-resource-collection>
  		<web-resource-name>JSP pages</web-resource-name>
  		<!-- 所有的jsp页面都不能被訪问 -->
  		<url-pattern>*.jsp</url-pattern>
  	</web-resource-collection>
  	<auth-constraint></auth-constraint>
  </security-constraint>
  
  <security-constraint>
  	<web-resource-collection>
  		<web-resource-name>Servlet1</web-resource-name>
  		<url-pattern>/servlet1</url-pattern>
  	</web-resource-collection>
  	<auth-constraint>
  		<role-name>member</role-name>
  		<role-name>manager</role-name>
  	</auth-constraint>
  </security-constraint>
  
  <login-config>
  <!-- BASIC必须所有大写 -->
  	<auth-method>BASIC</auth-method>
  	<!-- 显示在浏览器的登陆对话框中 -->
  	<realm-name>Members Only</realm-name>
  </login-config>
</web-app>

servlet1.java

package app11a.servlet;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(urlPatterns={"/servlet1"})
public class Servlet1 extends HttpServlet{

	private static final long serialVersionUID = 1L;
	
	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		RequestDispatcher dispatcher = request.getRequestDispatcher("/jsp/1.jsp") ;
		dispatcher.forward(request, response);
	}
}


因为映射到Servlet1的auth-constraint元素指定了manager和member两种角色,因此通过tom或者jerry都能够登录。

14.2.2、摘要訪问验证

摘要訪问验证,或简称摘要验证,它也是一种HTTP验证。与基本訪问验证相似。

摘要訪问验证不是使用软弱的Base64算法。而是用MD5算法创建一个散列。当中结合了username、relam名称以及password,并将这个散列发送到server。摘要訪问验证旨在代替基本訪问验证,由于她提供了更加安全的环境。

Servlet/JSP容器没有强制要求支持摘要訪问验证。可是大多数容器都支持。

将应用程序配置成使用摘要訪问验证,做法与使用基本訪问验证时相似。

其实。它们之间的唯一差别在于login-config元素中的auth-method元素的值。在摘要訪问验证中,这个元素的值必须为DIGEST(所有大写)。

以下就是举个样例使用了摘要訪问验证。

 web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
	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">
  <display-name></display-name>	
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  <security-constraint>
  	<web-resource-collection>
  		<web-resource-name>JSP pages</web-resource-name>
  		<!-- 全部的jsp页面都不能被訪问 -->
  		<url-pattern>*.jsp</url-pattern>
  	</web-resource-collection>
  	<auth-constraint></auth-constraint>
  </security-constraint>
  
  <security-constraint>
  	<web-resource-collection>
  		<web-resource-name>Servlet1</web-resource-name>
  		<url-pattern>/servlet1</url-pattern>
  	</web-resource-collection>
  	<auth-constraint>
  		<role-name>member</role-name>
  		<role-name>manager</role-name>
  	</auth-constraint>
  </security-constraint>
  
  <login-config>
  	<auth-method>DIGEST</auth-method>
  	<!-- 显示在浏览器的登陆对话框中 -->
  	<realm-name>Disest authentication</realm-name>
  </login-config>
</web-app>

打开浏览器输入http:/.localhost:8080/SingleUploadServlet/servlet1进行验证,又出现了刚才上面的页面。



14.2.3、基于表单的验证

基本和摘要訪问验证都不同意使用定制的登陆表单。假设你必须使用定制的表单。那么能够使用基于表单的验证方法。因为她所传输的值没有进行加密,因此这个应该与SSL结合起来使用。

使用基于表单的验证时,须要创建一个login页面和一个error页面。它们能够是HTML页面。也能够是JSP页面。

当第一次请求某一个受保护的资源时,Servlet/JSP容器将会发出Login页面。

登录成功后,再发出被请求的资源。

可是假设登录失败,用户将会看到Error页面。

使用基于表单的验证时,部署描写叙述符中的auth-method元素值必须设为FORM(所有大写)。此外,login-config元素必须有一个form-login-config元素,它带有两个子元素:form-login-pageform-error-page。以下就是在基于表单的验证中。login-config元素的范例。

<login-config>

<auth-method>FORM</auth-method>

<form-login-config>

<form-login-page>/login.html</form-login-page>

<form-error-page>/error.html</form-error-page>

</form-login-config>

</login-config>

以下是一个基于表单验证的样例:

web.xml

<?xml version="1.0" encoding="UTF-8"?

> <web-app version="3.0" 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"> <display-name></display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <security-constraint> <web-resource-collection> <web-resource-name>JSP pages</web-resource-name> <!-- 全部的jsp页面都不能被訪问 --> <url-pattern>*.jsp</url-pattern> </web-resource-collection> <auth-constraint></auth-constraint> </security-constraint> <security-constraint> <web-resource-collection> <web-resource-name>Servlet1</web-resource-name> <url-pattern>/servlet1</url-pattern> </web-resource-collection> <auth-constraint> <role-name>member</role-name> <role-name>manager</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/login.html</form-login-page> <form-error-page>/error.html</form-error-page> </form-login-config> </login-config> </web-app>


login.html

<!DOCTYPE html>
<html>
  <head>
    <title>Login</title>
	
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->

  </head>
  
  <body>
    <h1>Login Form</h1>
    <form action='j_security_check' method='post'>
    	<div>
    		User Name: <input name="j_username"/>
    	</div>
    	<div>
    		Password: <input type='password' name='j_password'/>
    	</div>
    	<div>
    		<input type='submit' value='Login'/>
    	</div>
    </form>
  </body>
</html>

error.html
<!DOCTYPE html>
<html>
  <head>
    <title>Login error</title>
	
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    
    <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->

  </head>
  
  <body>
    Login failed
  </body>
</html>

打开浏览器继续输入刚才的地址,会出来下面的页面:



client证书验证

client证书验证是在HTTPS(用SSL加密了的HTTP)上进行的,它要求每个client都要有一个client证书。这是一种很健壮的验证机制。可是不适用于在互联网上部署的应用程序。由于不可能要求每个互联网用户都拥有一个数字证书。然而。这样的验证方法能够用来訪问公司内部网的应用程序。

15.3SSL

SSLSecure Socket Layer,加密套接字层)协议最早是Netscape公司开发出来的,它能够针对互联网上的通信进行加密。同一时候确保数据的保密性和完整性。

14.3.1、password学

一開始。人们是利用对称加密进行加密和解密的。

在对称加密中。用同一个密钥对信息进行加密和解密。这是一种很easy的加密/解密技术。

如果,加密方法是用一个加密数字将字母表中的每个字母都往前移。因此,如果加密数字为2”ThisFriday”经过加密之后就变成了”VjkuHtkfca”。当你读完字母表时。又从头開始,因此y变成了a

接收方知道密钥为2,能够非常easy地破解信息。

可是。对称加密要求两方都要提前知道加密/解密的密钥。基于下面原因。对称加密不适用于互联网:

1、交换信息的两方常常是互相不认识的。

比如。在XX网上买书时,要将你的个人资料和信用卡资料发过去。假设使用对称加密术,你将不得不在进行交易之前给XX站点打电话。两方先确定下面密钥。

2、大家都希望可以与更多方进行通信。假设使用对称加密术。大家仅仅好保留很多不同的唯一密钥。每一个不同的通信方一个密钥。

3、因为你不认识即将进行通信的实体。因此必须确认对方是否真的是他们所生成的那个人。

4、在互联网上传递的信息要经过很多不同的计算机,因此要窃取别人的信息是非常easy地事情。

对称加密不能确保第三方不会篡改数据。

因此,当今互联网上的加密通信是採用非对称加密。它具有下面三个特征:

1、加密/解密。

加密过的信息对第三方隐藏了信息。仅仅有既定的接受方才干对信息进行解密。

2、验证。验证时证明某个实体是否为它所声明的那一个。

3、数据完整性。在互联网上发送的信息要传过很多计算机。因此必须确保所发送的数据没有被改动过,而且是完整的。

在非对称加密中,使用的是公钥加密法。在这样的加密方法中。数据的加密和解密是通过一对非对称的密钥来实现的,即一个公钥和一个私钥。

私钥是私人的,主人必须把它保存在一个安全的地方。绝不能被不论什么地方占有。

公钥则是分发给公众的。通常想要与这些公钥的主人进行通信时,就能够下载到。配对的公钥和私钥能够利用工具来生成。

公钥加密的魅力在于,用公钥加密的数据仅仅能利用相应的私钥才干进行解密;由此类推,用私钥加密的数据也仅仅能用相应的公钥才干进行解密。

这样的完美的算法是基于很巨大的质数,由麻省理工学院(MIT)的Ron RivestAdi ShamirLen Adleman发明与1977年。他们将这样的算法简单地称作RSA算法。即以它们三个人的姓的首字母组合而成。

14.3.2加密/解密

想要交换信息的两方中。必需要有偶乙方拥有一对密钥。如果Alice想要和Bob进行通信。Bob有一个公钥和一个私钥。Bob要将他的公钥发给AliceAlice就能够用它对要发给Bob的信息进行加密。仅仅有Bob能够对这些信息进行解密,由于他拥有相应的私钥。为了将信息发给AliceBob要利用它的私钥进行加密,Alice就能够用Bob的公钥进行解密。

可是,除非Bob可以亲自见到Alice并把它的公钥交给他。否则这样的方法就非常不完好了,单凡拥有密钥对的人们都可能声称自己是BobAlice根本无法查证。

在互联网上,交换信息的两方常常住的相隔遥远。见面一般是不太可能的。

14.3.3、验证

SSL中,验证是通过引入证书来解决的。

证书包括下面内容:

1、一个公钥

2、相关主题的信息。如公钥的全部者。

3、证书颁发商的名称。

4、某种时间戳,使证书过了一定的时期之后会过期。

证书最为关键的是。必须通过可I型男人的证书颁发商进行数字签名。比如VeriSign或者Thawte。对一个电子文档进行数字签名,就是将你的的签名加入到文档/文件里。原始文件没有进行加密,签名的真正目的是要确保文档/文件没有被篡改,对一个文档进行签名。要包含创建文档的摘要信息。并利用颁发商的私钥对摘要进行加密,为了查看这个文档是否仍然保持原封不动。要运行下面两个步骤:

1、利用签署者的公钥对文档的摘要信息进行解密。你非常快就会学到,可信任证书颁发商的公钥是非常easy获取到的。

2、给文档创建摘要信息。

3、将上述第一步和第二步的结果进行比較,假设这两个结果匹配,则表示文件没有被篡改。

这样的验证方法之所以可行,是由于仅仅有私钥的全部者可以对文档摘要进行解密,而且这个柴窑信息仅仅能通过相应公钥进行解密。增加你能确定自己全部拥有的是原版的公钥,那么就会知道这个文件有没有被改动过。

注意:因为证书能够通过可信任的证书颁发商进行数字签名,因此人们能够将他们的证书供大家公开下载,而不是採用他们的公钥。

证书颁发商会有一对公钥和私钥。

申请证书时。Bob必须生成一对密钥,并将其公钥发给证书颁发商,随后证书颁发商就会请Bob发一份护照或者其它身份证明给他,由此证明Bob的身份。对Bob晚上验证后,证书颁发商就会用它的私钥对证书进行签名。“签名”的意思就是加密。因此,证书仅仅能利用证书颁发商的公钥才干解毒。证书颁发商的公钥一般非常easy下载到。比如,差点儿全部主流浏览器都默认包括几家证书颁发商的公钥。

如今。有了数字证书之后,Bob在与别人交换信息之前,能够先公布他的数字证书,而不是公布他的公钥了。

其工作流程例如以下:

A->B Bob,你好!我要跟你通话。但我须要先确认下面你是否真实Bob

B->A 当然能够,这是我的证书。

A->B 这些还不够,我还须要你其它的身份证明资料。

B->A Alice,真的是我+[Bob的密钥加密过的信息摘要]

Bob发给Alice的最后一条信息中,也就是用Bob的公钥进行签名的那条消息,能够向Alice证明这条信息是可信的。

这就是验证的过程。

Alice联系BobBob将其证书发过去。

但是,光有证书还不够,由于不论什么人都可能得到Bob的证书。

别忘了,Bob但是将他的证书发给全部想要与他通信的人啊!

因此,Bob还要给她发送一条消息(“Alice。真的是我”)。并附上曾用其私钥对这条信息进行过加密的摘要。

Alice从证书中获得Bob的公钥。这个她能够做到,由于证书是利用证书颁发商的私钥签名的。Alice能够訪问证书颁发商的公钥(她的浏览器上就有一份)。

如今,她又收到一条消息,以及用Bob私钥加密过的摘要。Alice仅仅要给这条消息创建一个摘要。并将它与Bob发给她的加密摘要进行对照就可以。

Alice之所以能够解密,是由于它是用Bob的私钥加密的,而Alice又有一份Bob的公钥。假设两者匹配。Alice就能够确定对方就是真正的Bob

AliceBob完毕验证之后。第一件事就是发送一个加密密钥,这个将在接下来的信息交流中使用。使得,一但建立其了加密渠道。SSL就会採用对称加密法,由于它的速度要比不正确称加密法快得多。

这里还漏掉了一件事情没有交代。互联网上的信息要在很多计算机上传递的,那么你怎样确保哪些信息的完整性呢?由于在传输途中,不论什么人都可能截取那些信息啊。

14.3.4、数据完整性

如果Mallet是一个怀有恶意的人。他非常可能就坐在AliceBob之间,试图破解正在传递的消息,令Mallet遗憾的是,尽管他能够拷贝到信息。可是由于进行过加密,他并不知道密钥。但Mallet仍然可能破坏信息,或者不转播当中的某一个部分。为了解决问题,SSL引用了一个消息验证码(Message Authentication CodeMAC)。

MAC是通过一个密钥和一些数据传输计算出来的一组数据。由于Mallet不知道密钥。因此他无法算出摘要的正确值,信息的接受者则能够,而且因此能够发现是否有人试图破坏数据,或者发现数据是否不完整。如果答案是肯定的。那么两方能够停止通信。

这类信息摘要算法之中的一个为MD5,是由RSA发明的,很安全。

比如,假设使用128位的MAC值,那么恶意破坏者猜中正确值的几率大约为18 446 744 073 709 551 616分之中的一个。也就是说,差点儿永远不可能猜中。

14.3.5SSL工作原理

知道了SSL怎样解决加密/解密、验证及数据完整性的问题,如今来看一下SSL的工作原理。这次我们以Amazon(取代Bob)和一个买家(取代Alice)为例。

就像其它不论什么合法的电子商务卖家一样,Amazon也向一个可信任的证书颁发商申请了一份证书。买家使用的是IE浏览器,当中嵌有可信任的证书颁发商的公钥。买家并不须要真正了解SSL的工作原理,也不须要拥有公钥和私钥。他仅仅须要确保在输入重要的资料时,比如信用卡号码时,用HTTPS取代HTTP协议就可以。

这个必须显示在地址栏中的。

当买家输入一个加密页面(当他完毕购物时),在后台中,这个浏览器和Amazonserver之间会发生下面一系列事件。

浏览器:你真的是Amazon.com吗?

server:是的,这是我的证书。

然后,浏览器会利用证书颁发商的公钥进行解密,来验证证书的有效性。假设有哪里不正确,比如证书过期,浏览器就会向用户发出警告。假设用户不顾证书过期。允许继续,浏览器就会继续。

浏览器:光有证书还不够,请再发点别的身份证明给我。

server:我真的是Amazon.com+[这条信息用Amazon.com的私钥加密过的摘要]
浏览器利用Amazon的公钥对消息摘要进行解密,并未“我真的是Amazon.com”创建一条消息摘要。

假设两者匹配。表示验证成功。随后。浏览器就会产生一个随机密钥,利用Amazon的公钥对它进行加密。这个随机密钥将用于对兴许的消息进行加密和解密。换句话说,一旦完毕对Amazon的验证,就会採用对称加密,由于它的速度比飞对称加密要快得多。除了消息之外,两方还要发送消息摘要,以确保这些消息是完整的,没有被改动过。

14.4、通过编程确保安全性

虽然声明式安全简单易用,但偶尔还是须要通过编写代码来确保应用程序的安全性。

为此。能够在HttpServletRequest接口中使用安全注解类型和方法。

这两者都在以下进行讨论。

14.4.1、安全注解类型

javax.servlet.annotation包中与安全相关的3个注解类型是:ServletSecurityHttpConstraintHttpMethodConstraint

ServletSecurity注解能够带有valuehttpMethodConstraints属性。

httpConstraint注解类型用来定义一个安全约束,而且仅仅能赋给ServletSecurity注解的value属性。假设包括的ServletSecurity注解中没有出现httpMethodConstraints属性。那么HttpConstraint注解所强加的安全约束将应用于全部的HTTP方法。否则,安全约束将仅仅应用于httpMethodConstraints属性中定义的HTTP方法。比如,下面HttpConstraint注解表示所注解的Servlet仅仅能由manager角色中的訪客进行訪问。

@ServletSecurity(value = @HttpConstraint(rolesAllowed = “manager”))

当然。上述注解也能够改写成:

@ServletSecurity(@HttpConstraint(rolesAllowed = “manager”))

但仍然须要在部署描写叙述符中声明一个login-config元素,以便容器可以对用户进行验证。

将一个HttpConstraint注解的transportGuarantee属性设置为TransportGuarantee.CONFIDENTIAL。将使这个Servlet仅仅能通过某个秘密渠道进行訪问,比如SSL

@ServletSecurity(@HttpConstraint(transportGuarantee = TransportGuarantee.CONFIDENTIAL))

假设Servlet/JSP容器通过HTTP接收到针对这样的Servlet的请求。它会将浏览器重定向到该URLHTTPS版本号。

HttpMethodConstraint注解类型用于定义某个安全约束索要应用到的HTTP方法。它仅仅能放在ServletSecurity注解的httpMethodConstraints属性值数组中。比如,以下的httpMethodConstraint注解限制了仅仅有manager角色的用户能够通过HTTP Get訪问被注解的Servlet

对于其它的HTTP方法,则不存在不论什么限制。

@ServletSecurity(httpMethodConstraints = {@HttpMethodConstraint(value = “GET”, rolesAllowed = “manager”)})

注意,假设HttpMethodConstraint注解中没有出现rolesAllowed属性。那么所定义的HTTP方法将不受不论什么限制。

比如。下面的ServletSecurity注解中使用了valuehttpMethodConstraints这两个属性。

@ServletSecurity(value = @HttpConstraint(rolesAllowed = “manager”),

httpMethodConstraints = {@HttpMethodConstraint(“GET”)}

)

可是。假设HttpMethodConstraint注解类型的emptyRoleSemantic属性值为Empty-RoleSemantic.DENY,那么该方法将限制全部用户訪问。

比如,用下列ServletSecurity进行注解的Servlet,将禁止通过Get方法进行訪问。可是云溪member角色中的全部用户通过其它的HTTP方法进行訪问。

@ServletSecurity(value = @HttpConstraint(rolesAllowed = “member”),

httpMethodConstraints = {@HttpMethodConstraint(value = “GET”,

emptyRoleSemantic = EmptyRoleSemantic.DENY

)}

)

14.4.2Servlet安全API

除了利用注解类型,也能够在HttpServletRequest接口中利用下面方法来实现编程式的安全性。

java.lang.String getAuthType()

返回用来保护Servlet的验证方案。假设该Servlet中没有应用不论什么安全约束,则返回null

java.lang.String getRemoteUser()

返回发出该请求的用户的登录名。假设该用户未经验证,则返回null

boolean isUserInRole(java.lang.String role)

返回一个布尔值,表明该用户是否属于规定的角色。

java.lang.Principal getUserPrincipal()

返回一个包括当前被验证用户具体信息的java.security.Principal,假设该用户未经验证。则返回null

boolean authenticate(HttpServletResponse response) throws java.io.IOException

命令浏览器显示一个登录窗体。以便对用户进行验证。

void login(java.lang.String userName, java.lang.String password) throws javax.servlet.ServletException

通过提供的username和password进行登录,假设登录成功。该方法将不返回不论什么内容。否则,将抛出一个ServletException

void logout() throws javax.servlet.ServletException

注销用户

以下是一个样例,展示了怎样通过编程来完毕对用户的验证。

 ProgrammaticServlet.java

package servlet ;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(urlPatterns = {"/prog"})
public class ProgrammaticServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;
	
	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		if (request.authenticate(response)) {
			response.setContentType("text/html");
			PrintWriter out = response.getWriter() ;
			out.println("Welcome");
		} else {
			System.out.println("User not authenicated");
		}
	}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <login-config>
  	<auth-method>DIGEST</auth-method>
  	<realm-name>Digest authentication</realm-name>
  </login-config>
</web-app>
当用户第一次请求该Servlet时,用户还没有进行验证,验证方法将返回false。因此,Servlet/JSP容器会发出一个WWW-Authenticate标头,使浏览器显示一个登录对话框。进行摘要訪问验证。当用户提交填有正确username和password的表单时,authenticate方法返回true。并显示欢迎消息。


原文地址:https://www.cnblogs.com/yutingliuyl/p/6953503.html