Web應(yīng)用被應(yīng)用開(kāi)發(fā)者創(chuàng)建丽焊,這些開(kāi)發(fā)者給予啊奄、賣(mài)應(yīng)用,或者為了安裝到一個(gè)運(yùn)行時(shí)環(huán)境收叶,把應(yīng)用轉(zhuǎn)移應(yīng)用到一個(gè)部署者骄呼。應(yīng)用開(kāi)發(fā)者會(huì)把安全要求傳達(dá)給部署者和部署系統(tǒng)。這個(gè)信息可能會(huì)通過(guò)應(yīng)用的部署描述符或者在應(yīng)用代碼里使用注解明確地表達(dá)判没。
本章為了表達(dá)應(yīng)用的安全需求蜓萄,描述了Servlet容器安全機(jī)制、接口哆致、部署描述符和注解機(jī)制绕德。
一患膛、介紹
一個(gè)web應(yīng)用包含能被很多用戶(hù)訪問(wèn)的資源摊阀。這些資源通常在沒(méi)有保護(hù)和開(kāi)放網(wǎng)絡(luò)上傳輸,如Internet踪蹬。在這樣的環(huán)境中胞此,大量web應(yīng)用將會(huì)有安全需求。
雖然質(zhì)量保障和實(shí)現(xiàn)細(xì)節(jié)可能不同跃捣,servlet容器有機(jī)制和基礎(chǔ)設(shè)施來(lái)滿足共享下列特征的需求:
- Authentication: 交流實(shí)體要向?qū)Ψ阶C明它們是在授權(quán)的特殊身份上訪問(wèn)漱牵。
- Access control for resources: 與資源的交互被限制在用戶(hù)的集合中,或者為了強(qiáng)制一致性疚漆、可靠性或者可用性限制編程酣胀。
- Data Integrity: 這被用來(lái)證明在數(shù)據(jù)傳輸過(guò)程中刁赦,信息沒(méi)有被第三方修改。
- ** Confidentiality or Data Privacy:**這被用來(lái)保證信息僅對(duì)那些被授權(quán)的用戶(hù)訪問(wèn)闻镶。
二甚脉、聲明式安全
聲明式安全指表達(dá)一個(gè)應(yīng)用安全模型或者需求的方式,包括角色铆农,訪問(wèn)控制以及在一個(gè)應(yīng)用外部形勢(shì)的授權(quán)要求牺氨。部署描述符在web應(yīng)用中是主要的工具。
開(kāi)發(fā)者把應(yīng)用的邏輯安全需求映射到一個(gè)與具體運(yùn)行時(shí)環(huán)境相關(guān)的安全策略代表上墩剖。在運(yùn)行時(shí)中猴凹,servlet容器使用安全策略代表來(lái)強(qiáng)制認(rèn)證和授權(quán)。
安全模型應(yīng)用在web應(yīng)用中的靜態(tài)內(nèi)容部分和被客戶(hù)端請(qǐng)求的應(yīng)用中的servlets和filters上岭皂。當(dāng)一個(gè)servlet使用RequestDispatcher調(diào)用一個(gè)靜態(tài)資源或者使用一個(gè)forward或者include的servlet時(shí)郊霎,安全模型并不會(huì)應(yīng)用生效。
三爷绘、編程式安全
當(dāng)聲明式安全不足以表達(dá)應(yīng)用的安全模型時(shí)歹篓,編程式安全被安全意識(shí)應(yīng)用使用。編程式安全由HttpServletRequest接口的下列方法組成:
* authenticate
* login
* logout
* getRemoteUser
* isUserInRole
* getUserPrincipal
login方法允許一個(gè)應(yīng)用執(zhí)行用戶(hù)名和密碼集合(還有一種基于表單的登錄)揉阎。authenticate方法允許一個(gè)應(yīng)用從一個(gè)沒(méi)有限制的請(qǐng)求上下文中激起請(qǐng)求調(diào)用者的認(rèn)證庄撮。
logout方法允許一個(gè)應(yīng)用重置一個(gè)請(qǐng)求的調(diào)用身份。
getRemote方法返回與請(qǐng)求關(guān)聯(lián)的調(diào)用者名字毙籽。
isUserPrincipal方法決定與請(qǐng)求關(guān)聯(lián)的調(diào)用者是否是一個(gè)指定的安全角色洞斯。
getUserPrincipal方法決定了遠(yuǎn)端調(diào)用者的主要名字,并且返回一個(gè)與遠(yuǎn)端調(diào)用者對(duì)應(yīng)的java.security.Principal對(duì)象坑赡。在getUserPrincipal返回的Principal上調(diào)用getName方法會(huì)返回一個(gè)遠(yuǎn)端調(diào)用者的名字烙如。這些APIs允許servlets基于獲取的信息來(lái)決定業(yè)務(wù)邏輯。
如果沒(méi)有用戶(hù)已經(jīng)被授權(quán)毅否,getRemoteUser方法返回null亚铁,isUserInRole方法總會(huì)返回false,并且getUserPrincipal方法返回null螟加。
isUserInRole方法期望一個(gè)表示用戶(hù)角色名字的字符串參數(shù)徘溢。security-role-ref元素應(yīng)該在部署描述符中被聲明,并且有一個(gè)包含傳遞給方法的角色名字的role-name子元素捆探。一個(gè)security-role-ref元素應(yīng)該包含一個(gè)角色鏈接子元素然爆,它的值是用戶(hù)被映射到的安全角色的名字。當(dāng)決定調(diào)用的返回值時(shí)黍图,容器使用security-role-ref到security-role的映射曾雕。
比如,把安全角色引用FOO映射到名字為manager的安全角色助被。語(yǔ)法如下
<security-role-ref>
<role-name>FOO</role-name>
<role-link>manager</role-link>
</security-role-ref>
這個(gè)例子中剖张,如果被屬于manager安全角色的用戶(hù)調(diào)用的servlet調(diào)用API方法isUserInRole切诀,結(jié)果將會(huì)是true。
如果沒(méi)有匹配一個(gè)security-role的security-role-ref元素已經(jīng)被聲明搔弄,容器必須默認(rèn)對(duì)web應(yīng)用的security-role元素列表檢查role-name元素參數(shù)趾牧。isUserInRole方法參考這個(gè)列表來(lái)決定調(diào)用者是否被映射到一個(gè)安全角色。開(kāi)發(fā)者必須意識(shí)到這個(gè)默認(rèn)機(jī)制的使用在改變應(yīng)用中角色名字的時(shí)候限制靈活性肯污,改變角色名字不必重新編譯servlet來(lái)調(diào)用翘单。
四、編程式訪問(wèn)控制注解
本節(jié)定義了注解和apis蹦渣,用來(lái)配置Servlet容器強(qiáng)制的安全限制哄芜。
-
@ServletSecurity Annotation
@ServletSecurity注解為定義訪問(wèn)控制限制提供了一種替代機(jī)制,這等價(jià)于通過(guò)可移植部署描述符中的security-constraint元素聲明或者通過(guò)ServletRegistration接口的setServletSecurity方法編程式聲明柬唯。Servlet容器必須支持在實(shí)現(xiàn)了javax.servlet.Servlet 接口的類(lèi)上使用@ServletSecurity注解认臊。
package javax.servlet.annotation;
@Inherited
@Documented
@Target(value=TYPE)
@Retention(value=RUNTIME)
public @interface ServletSecurity {
HttpConstraint value();
HttpMethodConstraint[] httpMethodConstraints();
}
Table 1-1 ServletSecurity Interface
Element | 描述 | 默認(rèn) |
---|---|---|
value | HttpConstraint定義了應(yīng)用于所有沒(méi)出現(xiàn)在httpMethodConstraints返回?cái)?shù)組中的HTTP方法的保護(hù)。 | @HttpConstraint |
httpMethodConstraints | HTTP方法具體限制的數(shù)組 | {} |
@HttpConstraint
@HttpConstraint注解在@ServletSecurity注解中被使用來(lái)代表應(yīng)用于所有HTTP協(xié)議方法的安全限制锄奢,一個(gè)對(duì)應(yīng)的@HttpMethodConstraint沒(méi)有為上述方法出現(xiàn)在@ServletSecurity注解中失晴。
package javax.servlet.annotation
@Documented
@Retention(value=RUNTIME)
public @interface HttpConstraint {
ServletSecurity.EmptyRoleSemantic value();
java.lang.String[] rolesAllowed();
ServletSecurity.TransportGuarantee transportGuarantee();
}
Table 1-2 HttpConstraint接口
Element | 描述 | 默認(rèn) |
---|---|---|
value | 默認(rèn)的授權(quán)語(yǔ)義,僅當(dāng)rolesAllowed返回空數(shù)組時(shí)應(yīng)用拘央。 | PERMIT |
rolesAllowed | 包含授權(quán)角色名字的一個(gè)數(shù)組 | {} |
transportGuarantee | 數(shù)據(jù)保護(hù)要求涂屁,必須被請(qǐng)求到達(dá)的連接上被滿足 | NONE |
@HttpMethodConstraint
@HttpMethodConstraint注解在具體HTTP協(xié)議消息上代表安全限制的@ServletSecurity注解中被使用。
package javax.servlet.annotation
@Documented
@Retention(value=RUNTIME)
public @interface HttpMethodContraint {
ServletSecurity.EmptyRoleSemantic value();
java.lang.String[] rolesAllowed();
ServletSecurity.TransportGuarantee transportGuarantee();
}
Element | 描述 | 默認(rèn) |
---|---|---|
value | HTTP協(xié)議方法名字 | |
emptyRoleSemantic | 默認(rèn)授權(quán)機(jī)制灰伟,僅當(dāng)rolesAllowed返回空字符串時(shí)應(yīng)用 | PERMIT |
rolesAllowed | 包含已授權(quán)角色名字的一個(gè)數(shù)組 | {} |
transportGuarantee | 數(shù)據(jù)保護(hù)需求拆又,必須被請(qǐng)求到達(dá)的連接滿足 | NONE |
@ServletSecurity注解可以在一個(gè)Servlet實(shí)現(xiàn)類(lèi)上被指明,并且它的值被為根據(jù)元注解@Inherited規(guī)則定義的子類(lèi)繼承栏账。@ServletSecurity注解的一個(gè)實(shí)例可以出現(xiàn)在一個(gè)Servlet實(shí)現(xiàn)類(lèi)上面帖族,并且@ServletSecurity注解一定不能在一個(gè)Java方法上被指定。
當(dāng)一個(gè)或者多個(gè)@HttpMethodConstraint注解在一個(gè)@ServletSecurity注解里面被定義挡爵,每個(gè)@HttpMethodConstraint定義了security-constraint竖般,它應(yīng)用在所有HTTP協(xié)議方法上,而不是那些一個(gè)對(duì)應(yīng)HttpMethodConstraint在@ServletSecurity注解中被定義的方法上茶鹃。
定義在可移植部署描述符中的security-constraint元素對(duì)所有出現(xiàn)在限制里的url-patterns的有權(quán)限涣雕。
當(dāng)在可移植部署描述符中的一個(gè)security-constraint包含一個(gè)映射到一個(gè)用@ServletSecurity注解的類(lèi)的一個(gè)精確匹配的url-pattern,注解一定不能影響Servlet容器在pattern上的強(qiáng)行限制前计。
當(dāng)一個(gè)類(lèi)上沒(méi)有使用@ServletSecurity胞谭,應(yīng)用于從那個(gè)類(lèi)映射而來(lái)的一個(gè)servlet的訪問(wèn)策略(如果有的話)在對(duì)應(yīng)的部署描述符中被適用的security-constraint元素建立垃杖,或者除了任何這些元素男杈,通過(guò)ServletRegistration接口的setServletSecurity方法編程式地為目標(biāo)servlet建立。
例子
下列例子說(shuō)明了ServletSecurity注解的使用调俘。
CODE EXAMPLE 4-1 對(duì)于所有的HTTP方法伶棒,沒(méi)有限制
@ServletSecurity
public class Example1 extends HttpServlet {
}
CODE EXAMPLE 4-2 對(duì)所有HTTP方法旺垒,沒(méi)有授權(quán)約束,加密傳輸要求
@ServletSecurity(@HttpConstraint(transportGuarantee=TransportGuarantee.CONFIDENTIAL))
public class Example2 extends HttpServlet {
}
CODE EXAMPLE 4-3 對(duì)所有HTTP方法肤无,所有訪問(wèn)都被拒絕
@ServletSecurity(@HttpConstraint(EmptyRoleSemantic.DENY))
public class Example3 extends HttpServlet {
}
CODE EXAMPLE 4-4 對(duì)所有HTTP方法先蒋,要求角色R1成員的權(quán)限約束
@ServletSecurity(@HttpConstraint(rolesAllowed="R1"))
public class Example4 extends HttpServlet {
}
CODE EXAMPLE 4-5 對(duì)所有除了GET和POST的HTTP方法,沒(méi)有約束宛渐;對(duì)GET和POST方法竞漾,要求Role R1成員的權(quán)限約束,加密傳輸要求窥翩。
@ServletSecurity((httpMethodConstraints = { @HttpMethodConstraint(value="GET", rolesAllowed="R1"), @HttpMethodConstraint(value="POST", rolesAllowed="R1", transportGuarantee=TransportGuarantee.CONFIDENTIAL)})
public class Example5 extends HttpServlet {
}
CODE EXAMPLE 4-6 對(duì)除了GET的所有HTTP方法要求Role R1中成員的權(quán)限約束业岁,對(duì)于GET,沒(méi)有約束寇蚊。
@ServletSecurity(value = @HttpMethodConstraints(rolesAllowed = "R1"), httpMethodConstraints = @HttpMethodConstraint("Get"))
public class Example6 extends HttpServlet {
}
CODE EXAMPLE 4-7 對(duì)于除了TRACE的所有HTTP方法笔时,要求Role R1中成員的權(quán)限約束;對(duì)于TRACE仗岸, 所有訪問(wèn)都拒絕允耿。
@ServletSecurity(value = @HttpConstraint(rolesAllowed = "R1"), httpMethodConstraints = @HttpMethodConstraint(value="TRACE", emptyRoleSemantic = EmptyRoleSemantic.DENY))
public class Example7 extends HttpServlet {
}把@ServletSecurity映射到安全約束
本節(jié)描述了@ServletSecurity注解到它等價(jià)表示,如security-constraint 元素的映射扒怖。它使用已存在的容器security-constraint執(zhí)行機(jī)制來(lái)促進(jìn)執(zhí)行较锡。@ServletSecurity注解的強(qiáng)制性等價(jià)于security-constraint元素的強(qiáng)制性。
@ServletSecurity注解被用來(lái)定義一個(gè)方法依賴(lài)的@HttpConstraint盗痒,并且其后會(huì)跟著0個(gè)或者多個(gè)@HttpMethodConstraint說(shuō)明念链。方法依賴(lài)的約束應(yīng)用于所有沒(méi)有定義HTTP具體方法約束的HTTP方法。
當(dāng)沒(méi)有包含@HttpMethodConstraint元素积糯,對(duì)應(yīng)包含一個(gè)不含http-method元素的web-resource-collection的單個(gè)security-constraint元素的@ServletSecurity注解適用于所有HTTP方法掂墓。
下列例子描繪了一個(gè)不包含@HttpMethodConstraint注解作為單個(gè)security-constraint元素的@ServletSecurity注解表示。被對(duì)應(yīng)servlet定義的url-pattern元素將會(huì)被包含在web-resource-collection中看成,并且任何被包含的auth-constraint和user-data-constraint元素的出現(xiàn)和值將會(huì)通過(guò)@HttpConstraint值的映射被決定君编。
CODE EXAMPLE 4-8 映射不包含@HttpMethodConstraint的@ServletSecurity
@ServletSecurity(@HttpConstraint(rolesAllowed = "R1"))
<security-constraint>
<web-resource-collection>
<url-pattern>...</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>Role1</role-name>
<auth-constraint>
</security-constraint>
當(dāng)一個(gè)或者多個(gè)@HttpMethodConstraint元素被指定,方法依賴(lài)約束對(duì)應(yīng)單個(gè)security-constraint川慌,它包含一個(gè)為每個(gè)命名在具體方法下的HTTP方法限制于http-method-omission元素上的web-resource-collection吃嘿。每個(gè)@HttpMethodConstraint對(duì)應(yīng)于另外一個(gè)包含web-resource-collection的security-constraint,這個(gè)web-resource-collection包含一個(gè)命名對(duì)應(yīng)HTTP方法的http-method元素梦重。下列例子描繪了由單個(gè)約束的@HttpMethodConstraint的一個(gè)@ServletSecurity注解到兩個(gè)security-constraint元素的映射兑燥。被對(duì)應(yīng)servlet定義的url-pattern元素將會(huì)被包含在web-resource-collection中,并且任何包含auth-constraint和user-data-constraint元素的出現(xiàn)和元素將會(huì)通過(guò)相關(guān)@HttpConstraint和@HttpMethodConstraint值的映射來(lái)決定琴拧。
CODE EXAMPLE 4-9 映射包含@HttpMethodConstraint的@ServletSecurity
@ServletSecurity(value=@HttpConstraint(rolesAllowed = "Role1"), httpMethodConstraints = @HttpMethodConstraint(value = "TRACE", emptyRoleSemantic = EmptyRoleSemantic.DENY))
<security-constraint>
<web-resource-collection>
<url-pattern>...</url-pattern>
<http-method-omission>TRACE</http-method-omission>
</web-resource-collection>
<auth-constraint>
<role-name>Role1</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<url-pattern>...</url-pattern>
<http-method>TRACE</http-method>
</web-resource-collection>
</auth-constraint>
</security-constraint>-
映射@HttpConstraint和@HttpMethodConstraint到XML
本節(jié)描述了從@HttpConstraint和@HttpMethodConstraint注解值到它們auth-constraint和user-data-constraint表示的映射降瞳。這些注解為了表達(dá)在部署描述符中使用的auth-constraint和user-data-constraint元素的等價(jià)性共享一個(gè)公用模型。這個(gè)模型由下列3個(gè)元素組成:- emptyRoleSemantic
當(dāng)沒(méi)有角色被命名在rolesAllowed中時(shí),授權(quán)語(yǔ)義挣饥,PERMIT或者DENY應(yīng)用除师。這個(gè)元素的默認(rèn)值是PERMIT,并且DENY在聯(lián)合使用一個(gè)非空rolesAllowed列表中并不被支持扔枫。 - rolesAllowed
這是一個(gè)包含已授權(quán)角色名字的列表汛聚。當(dāng)這個(gè)列表為空,它的含義取決于emptyRoleSemantic的值短荐。當(dāng)包含在允許角色的列表中時(shí)倚舀,角色名字"*"沒(méi)有特殊含義。這個(gè)元素的默認(rèn)值是一個(gè)空列表忍宋。 - TransportGuarantee
無(wú)論是NONE或者CONFIDENTIAL瞄桨,數(shù)據(jù)保護(hù)需求必須被請(qǐng)求到達(dá)的連接滿足。這個(gè)元素等價(jià)于包含有對(duì)應(yīng)值的transport-guarantee元素的user-data-constraint讶踪。這個(gè)元素的默認(rèn)值是NONE芯侥。
下列例子描繪了@HttpConstraint模型和web.xml中的auth-constraint及transport-guarantee元素之間的對(duì)應(yīng)關(guān)系。
CODE EXAMPLE 4-10 emptyRoleSemantic=PERMIT,rolesAllowed={},transportGuarantee=NONE
沒(méi)有限制
CODE EXAMPLE 4-11 emptyRoleSemantic=PERMIT,rolesAllowed={},transportGuarantee=CONFIDENTIAL
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
CODE EXAMPLE 4-12 emptyRoleSemantic=PERMIT,rolesAllowed={Role1},transportGuarantee=NONE
<auth-constraint>
<security-role-name>Role1</security-role-name>
</auth-constraint>
CODE EXAMPLE 4-13 emptyRoleSemantic=PERMIT,rolesAllowed={Role1},transportGuarantee=CONFIDENTIAL
<auth-constraint>
<security-role-name>Role1</security-role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
CODE EXAMPLE 4-14 emptyRoleSemantic=DENY,rolesAllowed={},transportGuarantee=NONE
<auth-constraint/>
CODE EXAMPLE 4-15 emptyRoleSemantic=DENY,rolesAllowed={},transportGuarantee=CONFIDENTIAL
<auth-constraint/>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
- emptyRoleSemantic
-
ServletRegistration.Dynamic的setServletSecurity
setServletSecurity方法可以在ServletContextListener中被用來(lái)定義應(yīng)用于為ServletRegistration定義的映射的安全約束乳讥。
Collection<String> setServletSecurity(ServletSecurityElement arg)
傳遞給serServletSecurity的javax.servlet.ServletSecurityElement參數(shù)類(lèi)似@ServletSecurity注解的ServletSecurity接口的結(jié)構(gòu)和模型柱查。Mapping @ServletSecurity to security-constraint節(jié)中定義的映射關(guān)系類(lèi)似于一個(gè)包含HttpConstraintElement和HttpMethodConstraintElement值的ServletSecurityElement元素的映射,等價(jià)于security-constraint表示云石。
setServletSecurity方法返回已經(jīng)是部署描述符(因此不會(huì)被調(diào)用影響)中security-constraint元素的精確目標(biāo)的URL模式的集合(可能為空)唉工。
如果ServletsContext(ServletRegistration從這里獲取到)已經(jīng)被初始化,那么這個(gè)方法將會(huì)拋出一個(gè)IllegalStateException汹忠。
當(dāng)部署描述符中的一個(gè)security-constraint包含一個(gè)url-pattern淋硝,這個(gè)url-pattern是一個(gè)被ServletRegistration映射的模式的精確匹配,那么調(diào)用ServletRegistration之上的setServletSecurity一定不能影響Servlet容器在模式上的強(qiáng)制約束宽菜。
有上述列出的異常以及包含何時(shí)Servlet類(lèi)被@ServletSecurity注解谣膳,何時(shí)setServletSecurity在ServletRegistration上被調(diào)用,它會(huì)建立應(yīng)用于registration的url-pattern的安全約束铅乡。
五继谚、角色
一個(gè)安全角色是一個(gè)被應(yīng)用開(kāi)發(fā)者或者裝配器定義的用戶(hù)邏輯分組。當(dāng)應(yīng)用被部署阵幸,角色被一個(gè)開(kāi)發(fā)者映射到運(yùn)行時(shí)中的委托者或者組花履。
一個(gè)servlet容器為關(guān)聯(lián)一個(gè)基于主體安全屬性進(jìn)來(lái)的請(qǐng)求的主體強(qiáng)制執(zhí)行聲明式或者編程式安全。
這可以在下述方式的任意一種中發(fā)生:
- 一個(gè)開(kāi)發(fā)者已經(jīng)在運(yùn)行環(huán)境中把一個(gè)安全角色映射到一個(gè)用戶(hù)組挚赊。調(diào)用主體所在的用戶(hù)組從它們的安全屬性中被檢索诡壁。僅當(dāng)主體屬于安全角色已經(jīng)被開(kāi)發(fā)者映射到的用戶(hù)組,主體才是在安全角色中荠割。
- 一個(gè)開(kāi)發(fā)者已經(jīng)把一個(gè)安全角色映射到一個(gè)安全策略域中的一個(gè)主體名字妹卿。這種情況下,調(diào)用主體的主體名字從它們的安全屬性中檢索。僅當(dāng)主體名與安全角色被映射到的主體名一樣時(shí)纽帖,主體就在安全角色中宠漩。
六举反、認(rèn)證
一個(gè)web客戶(hù)端能夠使用下列機(jī)制中的一種來(lái)給一個(gè)web服務(wù)器驗(yàn)證用戶(hù)身份:
- HTTP Basic Authentication
- HTTP Digest Authentication
- HTTPS Client Authentication
- Form Based Authentication
-
HTTP Basic Authentication
HTTP Basic Authentication懊直,基于用戶(hù)名和密碼,是定義在HTTP/1.0規(guī)范中的認(rèn)證機(jī)制火鼻。一個(gè)web服務(wù)器請(qǐng)求一個(gè)web客戶(hù)端來(lái)驗(yàn)證這個(gè)用戶(hù)室囊。作為請(qǐng)求的一部分,web服務(wù)器會(huì)傳遞一個(gè)字符串realm魁索,用戶(hù)會(huì)在這個(gè)里面被認(rèn)證融撞。web客戶(hù)端從用戶(hù)獲取用戶(hù)名和密碼,然后把它們傳遞給web服務(wù)器粗蔚。web服務(wù)器會(huì)在具體的realm中驗(yàn)證用戶(hù)尝偎。
Basic Authentication并不是一個(gè)安全認(rèn)證協(xié)議。用戶(hù)密碼以簡(jiǎn)單的base64編碼發(fā)送鹏控,并且目標(biāo)服務(wù)器沒(méi)有被驗(yàn)證致扯。額外的保護(hù)能夠緩解一些擔(dān)心:一個(gè)安全傳輸機(jī)制(HTTPS), 或者網(wǎng)絡(luò)級(jí)別的安全在一些部署場(chǎng)景下被應(yīng)用。 -
HTTP Digest Authentication
像HTTP Basic Authentication当辐,HTTP Digest Authentication基于一個(gè)用戶(hù)名和密碼驗(yàn)證一個(gè)用戶(hù)抖僵。然而,不像HTTP Basic Authentication缘揪,HTTP Digest Authentication不會(huì)在網(wǎng)絡(luò)上發(fā)送用戶(hù)密碼耍群。在HTTP Digest Authentication中,客戶(hù)端發(fā)送一個(gè)密碼的單向加密哈希(以及額外的數(shù)據(jù))找筝。盡管密碼不會(huì)在電纜上發(fā)送蹈垢,但是HTTP Digest Authentication要求明文密碼等價(jià)物對(duì)驗(yàn)證容器可用,以便容器能夠驗(yàn)證收到的通過(guò)計(jì)算預(yù)期數(shù)字的驗(yàn)證器袖裕。Servlet容器應(yīng)該支持HTTP_DIGEST驗(yàn)證耘婚。 -
Form Based Authentication
login screen的外觀和感覺(jué)在使用web瀏覽器的內(nèi)置驗(yàn)證機(jī)制時(shí)不能不同。本規(guī)范介紹了一個(gè)必須的form based authentication機(jī)制陆赋,它允許一個(gè)開(kāi)發(fā)者控制登錄界面的外觀和感覺(jué)沐祷。
web應(yīng)用部署描述符包含了登錄表單的錯(cuò)誤頁(yè)面的入口。登錄表單必須包含用來(lái)輸入用戶(hù)名和密碼的域攒岛。這些域必須分別命名為j_username和j_password赖临。
當(dāng)一個(gè)用戶(hù)嘗試獲取受保護(hù)的web資源,容器會(huì)檢查用戶(hù)的身份認(rèn)證灾锯。如果用戶(hù)被認(rèn)證兢榨,并且擁有訪問(wèn)資源的權(quán)限,請(qǐng)求的web資源被激活,并且執(zhí)行它的一個(gè)引用被返回吵聪。
如果用戶(hù)沒(méi)有被認(rèn)證凌那,所有下述步驟會(huì)出現(xiàn): - 與安全約束相關(guān)的登錄表單被發(fā)送給客戶(hù)端,并且觸發(fā)認(rèn)證的URL路徑被容器存儲(chǔ)吟逝。
- 用戶(hù)被讓填寫(xiě)表單帽蝶,包括用戶(hù)名和密碼。
- 客戶(hù)端把表單以post方式發(fā)回給服務(wù)器块攒。
- 容器嘗試使用表單中的信息驗(yàn)證用戶(hù)励稳。
- 如果驗(yàn)證失敗,使用發(fā)送或者重定向的方式返回一個(gè)錯(cuò)誤頁(yè)面囱井,并且response的狀態(tài)碼被設(shè)置為200驹尼。
- 如果驗(yàn)證成功,認(rèn)證用戶(hù)的主體被檢查庞呕,看它是否在獲取資源的授權(quán)角色中新翎。
- 如果用戶(hù)被認(rèn)證,客戶(hù)端使用存儲(chǔ)的URL路徑被重定向到資源住练。
發(fā)送給為通過(guò)驗(yàn)證的用戶(hù)的錯(cuò)誤頁(yè)面包含失敗的信息地啰。
Form Based Authentication如Basic Authentication一樣缺乏安全,因?yàn)橛脩?hù)密碼被作為普通文本被發(fā)送澎羞,并且目標(biāo)服務(wù)器沒(méi)有被驗(yàn)證髓绽。額外的保護(hù)能夠緩解一些擔(dān)憂:一個(gè)安全傳輸機(jī)制(HTTPS), 或者網(wǎng)絡(luò)級(jí)別的安全在一些部署場(chǎng)景下被應(yīng)用。
表單登錄注意事項(xiàng)
基于表單的登錄和基于URL的會(huì)話跟蹤可能是有問(wèn)題的實(shí)現(xiàn)妆绞。僅當(dāng)會(huì)話被cookies或者SSL session信息維護(hù)的時(shí)候顺呕,基于表單的登錄才應(yīng)該被使用。
為了進(jìn)行適當(dāng)?shù)尿?yàn)證括饶,登錄表單的動(dòng)作必須總是j_security_check株茶。做這個(gè)限制以便登錄表單無(wú)論是哪個(gè)資源都能正常工作,并且避免要求服務(wù)器指定表單之外的動(dòng)作域图焰。
這是一個(gè)展示表單如何被編碼到HTML頁(yè)面中的例子:
<form method="POST" action="j_security_check">
<input type="text" name="j_username">
<input type="password" name="j_password">
</form>
如果基于表單的登錄由于一個(gè)HTTP請(qǐng)求被調(diào)用启盛,原始請(qǐng)求的參數(shù)必須被容器保留,如果成功通過(guò)驗(yàn)證技羔,它會(huì)把調(diào)用重定向到一個(gè)請(qǐng)求的資源僵闯。
如果用戶(hù)使用表單登錄通過(guò)驗(yàn)證,并且已經(jīng)創(chuàng)建一個(gè)HTTP會(huì)話藤滥,會(huì)話的超時(shí)或者非法導(dǎo)致用戶(hù)在后續(xù)請(qǐng)求必須引發(fā)用戶(hù)被重新認(rèn)證的場(chǎng)景下被登出鳖粟。登出的范圍與認(rèn)證的一樣:比如,如果容器支持單點(diǎn)登錄拙绊,如兼容Java EE技術(shù)的web容器向图,用戶(hù)將需要和位于web容器的任何web應(yīng)用重新認(rèn)證泳秀。HTTPS Client Authentication
使用HTTPS(HTTP over SSL)的終端用戶(hù)認(rèn)證是一個(gè)很強(qiáng)的認(rèn)證機(jī)制。這種機(jī)制需要客戶(hù)端擁有一個(gè)Public Key Certificate(PKC)榄攀。當(dāng)前PKCs在電商應(yīng)用中很有用嗜傅,并且在瀏覽器中的單點(diǎn)登錄中也很有用。
- 其它容器認(rèn)證機(jī)制
Servlet容器應(yīng)該提供一個(gè)公共接口檩赢,可以通過(guò)部署的應(yīng)用的容器被用來(lái)集成和配置額外的HTTP消息層認(rèn)證機(jī)制吕嘀。這些接口應(yīng)該被提供給締約方使用,而不是給容器提供商(包括應(yīng)用開(kāi)發(fā)者漠畜,系統(tǒng)管理員币他,和系統(tǒng)集成者)坞靶。
為了促進(jìn)便攜實(shí)現(xiàn)和額外容器認(rèn)證機(jī)制的集成憔狞,推薦所有Servlet容器實(shí)現(xiàn)給容器提供的Java 認(rèn)證SPI的Servlet Container Profile。SPI可以在這里下載:http://www.jcp.org/en/jsr/detail?id=196彰阴。
七瘾敢、認(rèn)證信息的服務(wù)器跟蹤
在運(yùn)行時(shí)環(huán)境中角色被映射到的當(dāng)前安全身份(如用戶(hù)和組)是具體環(huán)境,而不是具體應(yīng)用尿这,它期望是:
- 做web應(yīng)用部署的環(huán)境中的登錄機(jī)制和策略簇抵。
- 能夠使用相同的認(rèn)證信息來(lái)對(duì)所有部署在同一個(gè)容器的應(yīng)用代表一個(gè)主體。
- 僅當(dāng)跨越了一個(gè)安全策略域邊界射众,才需要用戶(hù)的重新認(rèn)證碟摆。
因此,一個(gè)servlet容器被要求在容器級(jí)別跟蹤認(rèn)證信息(而不是web應(yīng)用級(jí)別)叨橱。這允許對(duì)一個(gè)web應(yīng)用已經(jīng)認(rèn)證的用戶(hù)訪問(wèn)被其它擁有同樣安全身份的容器管理的資源典蜕。
八、指定安全約束
安全約束是定義web內(nèi)容保護(hù)的一個(gè)聲明方式罗洗。一個(gè)安全約束與認(rèn)證關(guān)聯(lián)愉舔,用戶(hù)數(shù)據(jù)與web資源上的HTTP操作關(guān)聯(lián)。一個(gè)安全約束伙菜,在部署描述中被security-constration表示轩缤,由下列元素組成:
- web資源集合(部署描述符中的web-resource-collection)
- 認(rèn)證約束(部署描述符中的auth-constraint)
- 用戶(hù)數(shù)據(jù)約束(部署描述符中的user-data-constraint)
HTTP操作和安全約束應(yīng)用于的web資源被一個(gè)或者多個(gè)web資源集合識(shí)別。一個(gè)web資源集合由下列元素組成: - URL patterns(部署描述符中的url-pattern)
- HTTP方法(部署描述符中的http-method和http-method-omission元素)
一個(gè)認(rèn)證約束為認(rèn)證和認(rèn)證角色允許執(zhí)行約束請(qǐng)求的名字建立一個(gè)要求贩绕。一個(gè)用戶(hù)必須是允許執(zhí)行約束請(qǐng)求的角色的一個(gè)成員火的。特殊的角色名字"*"是對(duì)定義在部署描述符中定義的所有角色名字的一個(gè)簡(jiǎn)稱(chēng)。一個(gè)沒(méi)有命名角色的認(rèn)證約束表明訪問(wèn)約束請(qǐng)求一定不能在任何環(huán)境下被允許淑倾。一個(gè)認(rèn)證約束由下列元素組成: - 角色名字(部署描述符role-name)
一個(gè)用戶(hù)數(shù)據(jù)約束建立一個(gè)必要條件:一個(gè)約束的請(qǐng)求在受保護(hù)傳輸層連接上被接收馏鹤。所需保護(hù)的強(qiáng)度被傳輸保證的值定義。一個(gè)INTEGRAL的傳輸保證被用來(lái)為內(nèi)容完整性建立一個(gè)必要條件踊淳,并且一個(gè)CONFIDENTIAL的傳輸保證被用來(lái)為加密簡(jiǎn)歷一個(gè)必要條件假瞬。NONE的傳輸保證表明當(dāng)在任何包含一個(gè)未受保護(hù)的連接上被接收時(shí)陕靠,容器必須接收約束的請(qǐng)求。一個(gè)用戶(hù)數(shù)據(jù)約束有下列元素組成: - transport guarantee(部署描述符中的transport-guarantee)
如果沒(méi)有認(rèn)證約束應(yīng)用于一個(gè)請(qǐng)求脱茉,容器必須接收請(qǐng)求剪芥,而不需要用戶(hù)認(rèn)證。如果沒(méi)有用戶(hù)數(shù)據(jù)約束應(yīng)用于一個(gè)請(qǐng)求琴许,當(dāng)在任何包含一個(gè)未受保護(hù)的連接上被接收時(shí)税肪,容器必須接收請(qǐng)求
-
聯(lián)合約束
為了聯(lián)合約束的目的,當(dāng)沒(méi)有HTTP方法在集合中被命名榜田,或者集合特地在一個(gè)被包含的http-method元素中特地命名了HTTP方法益兄,或者集合包含一個(gè)或者更多http-method-omission元素,沒(méi)有元素命名這個(gè)HTTP方法時(shí)箭券,一個(gè)HTTP方法會(huì)在一個(gè)web-resource-collection中出現(xiàn)净捅。
當(dāng)一個(gè)url-pattern和HTTP方法對(duì)在多個(gè)安全約束下出現(xiàn)在聯(lián)合(比如在一個(gè)web-resource-collection中)中,這個(gè)約束(在pattern和方法上)通過(guò)聯(lián)合單獨(dú)的約束來(lái)定義辩块。對(duì)相同pattern和方法出現(xiàn)的聯(lián)合約束規(guī)則如下:
- 命名角色或者通過(guò)名字"*"說(shuō)明角色的認(rèn)證約束的聯(lián)合將會(huì)產(chǎn)生單個(gè)約束中角色名字的并集蛔六。一個(gè)不包含一個(gè)認(rèn)證約束的安全約束將會(huì)結(jié)合命名或者暗示角色的認(rèn)證約束來(lái)允許未認(rèn)證約束。一個(gè)沒(méi)有命名角色的認(rèn)證約束的特殊例子將聯(lián)合其它任何約束來(lái)重寫(xiě)它們的影響并且訪問(wèn)被阻止废亭。
- 應(yīng)用于一個(gè)普通url-pattern的user-data-constraints和http-method的聯(lián)合將會(huì)產(chǎn)生被單個(gè)約束接收的連接類(lèi)型的并集国章。一個(gè)并不包含一個(gè)user-data-constraint的安全約束將會(huì)與其它user-data-constraint聯(lián)合來(lái)讓未保護(hù)的連接類(lèi)型成為一個(gè)可接收的連接類(lèi)型。
- 例子
下列例子說(shuō)明了約束的聯(lián)合以及它們到一個(gè)應(yīng)用約束表格的轉(zhuǎn)換豆村。假設(shè)一個(gè)部署描述符包含下列安全限制:
<security-constraint>
<web-resource-collection>
<web-resource-name>preclued methods</web-resource-name>
<url-pattern>/</url-pattern>
<url-pattern>/acme/wholesale/</url-pattern>
<url-pattern>/acme/retail/</url-pattern>
<http-method-omission>GET</http-method-omission>
<http-method-omission>POST</http-method-omission>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>wholesale</web-resource-name>
<url-pattern>/acme/wholesale/</url-pattern>
<http-method>GET</http-method>
<http-method>PUT</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>SALEACLERK</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>wholesale 2</web-resource-name>
<url-pattern>/acme/wholesale/</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>CONTRACTOR</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>retail</web-resource-name>
<url-pattern>/acme/retail/</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>CONTRACTOR</role-name>
<role-name>HOMEOWNER</role-name>
</auth-constraint>
</security-constraint>
這個(gè)假想部署描述符的轉(zhuǎn)換將會(huì)產(chǎn)生下表中定義的約束:
TABLE 安全約束表
url-pattern | http-method | permitted roles | 支持的連接類(lèi)型 |
---|---|---|---|
/* | 除了GET液兽、POST的所有方法 | 訪問(wèn)拒絕 | 沒(méi)有約束 |
/acme/wholesale/* | 除了GET兄世、POST的所有方法 | 訪問(wèn)拒絕 | 沒(méi)有約束 |
/acme/wholesale/* | GET | CONTRACTOR SALESCLERK | 沒(méi)有約束 |
/acme/wholesale/* | POST | CONTRACTOR | CONFIDENTIAL |
/acme/retail/* | 除了GET盛正、POST的所有方法 | 訪問(wèn)拒絕 | 沒(méi)有約束 |
/acme/retail/* | GET | CONTRACTOR HOMEOWNER | 沒(méi)有約束 |
/acme/retail/* | POST | CONTRACTOR HOMEOWNER | 沒(méi)有約束 |
- 處理請(qǐng)求
當(dāng)servlet容器接收一個(gè)請(qǐng)求拍棕,它將會(huì)使用Use of URL Paths中描述的算法來(lái)選擇是請(qǐng)求URI的最佳匹配的url-pattern上定義的約束(如果有)剑勾。如果沒(méi)有約束被選擇颠黎,容器將會(huì)接收請(qǐng)求喳资。否則容器將會(huì)決定請(qǐng)求的HTTP方法是否在選擇的模式上被約束掉伏。如果不是巩剖,請(qǐng)求將會(huì)被接收适滓。否則敦迄,請(qǐng)求必須在url-pattern上滿足應(yīng)用于HTTP方法的約束。下列兩條規(guī)則必須滿足將被接收的請(qǐng)求并且分發(fā)給關(guān)聯(lián)servlet凭迹。 - 請(qǐng)求被接收連接上的特點(diǎn)必須滿足至少一個(gè)被約束定義的支持連接類(lèi)型罚屋。如果這條規(guī)則不被滿足,容器將會(huì)拒絕請(qǐng)求并且會(huì)重定向到HTTPS端口嗅绸。
- 請(qǐng)求的認(rèn)證特點(diǎn)必須滿足任何認(rèn)證和通過(guò)約束定義的角色要求脾猛。如果這條規(guī)則由于訪問(wèn)被拒絕(通過(guò)一個(gè)認(rèn)證約束沒(méi)有命名角色)而不被滿足,請(qǐng)求將會(huì)按照禁止?fàn)顟B(tài)被拒絕并且403(SC_FORBIDDEN)狀態(tài)碼將會(huì)被返回給用戶(hù)鱼鸠。如果訪問(wèn)被限制允許角色并且請(qǐng)求還沒(méi)有被認(rèn)證猛拴,請(qǐng)求將會(huì)因?yàn)槲凑J(rèn)證被拒絕羹铅,并且401(SC_UNAUTHORIZED)狀態(tài)碼將會(huì)返回給原因認(rèn)證。如果訪問(wèn)被限制允許角色并且請(qǐng)求的認(rèn)證身份不是這些角色中任何一個(gè)的成員愉昆,請(qǐng)求將會(huì)因?yàn)榻贡痪芙^职员,并且一個(gè)403(SC_FORBIDDEN)狀態(tài)碼將會(huì)被返回給用戶(hù)。
九跛溉、默認(rèn)策略
默認(rèn)地焊切,訪問(wèn)資源不需要被認(rèn)證。當(dāng)包含是請(qǐng)求URI最佳匹配的url-pattern的安全約束(如果有)在請(qǐng)求的HTTP方法上結(jié)合實(shí)施一個(gè)auth-constraint(命名角色)時(shí)芳室,認(rèn)證是必要的专肪。相似地,一個(gè)受保護(hù)的傳輸并不必要堪侯,除非應(yīng)用于請(qǐng)求上的安全約束在請(qǐng)求的HTTP方法上結(jié)合實(shí)施一個(gè)user-data-constraint(帶一個(gè)受保護(hù)的transport-guarantee)嚎尤。
十、登錄和登出
把一個(gè)請(qǐng)求分發(fā)給servlet引擎時(shí)抖格,容器建立請(qǐng)求的調(diào)用者身份诺苹。調(diào)用者身份在整個(gè)請(qǐng)求處理過(guò)程中保持不變咕晋,或者直到應(yīng)用在request上成功調(diào)用authenticate雹拄,login或者logout。
請(qǐng)求處理期間被記錄到一個(gè)應(yīng)用中掌呜,由于可以通過(guò)調(diào)用request上的getRemoteUser或者getUserPrincipal滓玖,精確對(duì)應(yīng)一個(gè)與請(qǐng)求關(guān)聯(lián)的合法非空調(diào)用者身份。一個(gè)來(lái)自任意這些方法的null返回值表明調(diào)用者在請(qǐng)求處理時(shí)沒(méi)有被記錄進(jìn)應(yīng)用中质蕉。
容器可以穿件一個(gè)HTTP會(huì)話對(duì)象來(lái)跟蹤登錄狀態(tài)势篡。如果一個(gè)開(kāi)發(fā)者創(chuàng)建了一個(gè)會(huì)話,同時(shí)一個(gè)用戶(hù)沒(méi)有被認(rèn)證模暗,那么容器會(huì)認(rèn)證這個(gè)用戶(hù)禁悠,登錄之后對(duì)開(kāi)發(fā)者代碼的會(huì)話可見(jiàn)性必須是同一個(gè)會(huì)話對(duì)象,這個(gè)對(duì)象在登錄出現(xiàn)之前被創(chuàng)建兑宇,以便沒(méi)有會(huì)話信息的丟失碍侦。
翻譯自 Java Servlet Specification
Version 3.0 Rev a
Author:Rajiv Mordani
Date: December 2010