Jetty:配置安全

用${jetty.home}和${jetty.base}配置安全

Jetty 9.1中:

1)${jetty.home}是jetty发布(二进制)的目录路径;

2)${jetty.base}是用户定制化的目录路径。

这样分化:

1)允许你管理多个Jetty安装;

2)当你升级Jetty后,更容易保留你当前的配置。

更多的信息在后面讲《启动Jetty》时会详述。

而且,Jetty 9.1参数化了所有的标准XML配置。例如SSL,参数现在仅是在start.ini中的属性,不需要编辑XML文件。

Jetty 9.1也使用模块。Jetty不再直接的为一个特征列出所有的库、属性和XML文件,改为使用软件模块,并且start.jar机制允许你创建新模块。你定义一个模块在一个modules/*.mod文件中,包括库、依赖、XML、和模板INI文件。你只需要用--module=name命令行选项即可加载模块。模块使用依赖来控制库和XML文件的顺序,更多的信息在《启动Jetty》讲述。

在Jetty 9.1中配置SSL

下面是一个使用${jetty.home}和${jetty.base}配置SSL的例子,其中也包括了模块怎么工作的细节。

这个例子假定你的Jetty发布放在/home/user/jetty-distribution-9.1.0.RC0。

1)创建一个base文件夹

[/home/user]$ mkdir my-base
[/home/user]$ cd my-base

2)为SSL、HTTP和webapp部署增加模块

[my-base]$ java -jar /home/user/jetty-distribution-9.1.0.RC0/start.jar --add-to-start=ssl,http,deploy

ssl             initialised in ${jetty.base}/start.ini (appended)
ssl             enabled in     ${jetty.base}/start.ini
DOWNLOAD: http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/plain/jetty-server/src/main/config/etc/keystore to etc/keystore
server          initialised in ${jetty.base}/start.ini (appended)
server          enabled in     ${jetty.base}/start.ini
http            initialised in ${jetty.base}/start.ini (appended)
http            enabled in     ${jetty.base}/start.ini
server          enabled in     ${jetty.base}/start.ini
deploy          initialised in ${jetty.base}/start.ini (appended)
deploy          enabled in     ${jetty.base}/start.ini
MKDIR: ${jetty.base}/webapps
server          enabled in     ${jetty.base}/start.ini

3)查看你的文件夹

[my-base]$ ls -la
total 20
drwxrwxr-x   4 user group 4096 Oct  8 06:55 ./
drwxr-xr-x 103 user group 4096 Oct  8 06:53 ../
drwxrwxr-x   2 user group 4096 Oct  8 06:55 etc/
-rw-rw-r--   1 user group  815 Oct  8 06:55 start.ini
drwxrwxr-x   2 user group 4096 Oct  8 06:55 webapps/

4)拷贝你的WAR文件到webapps

[my-base]$ ls -la
[my-base]$ cp ~/code/project/target/gadget.war webapps/

5)拷贝你的keystore

[my-base]$ cp ~/code/project/keystore etc/keystore

6)编辑start.ini配置你的SSL设置

[my-base]$ cat start.ini

7)初始化模块ssl

--module=ssl

8)为安全重定向定义端口

jetty.secure.port=8443

9)建立一个示范keystore和truststore

jetty.keystore=etc/keystore
jetty.truststore=etc/keystore

10)设置示范密码

jetty.keystore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
jetty.keymanager.password=OBF:1u2u1wml1z7s1z7a1wnl1u2g
jetty.truststore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4

11)初始化模块server

--module=server
threads.min=10
threads.max=200
threads.timeout=60000
#jetty.host=myhost.com
jetty.dump.start=false
jetty.dump.stop=false

12)初始化模块http

--module=http
jetty.port=8080
http.timeout=30000

13)初始化模块部署

--module=deploy

查看你现在的配置:

[my-base]$ java -jar /home/user/jetty-distribution-9.1.0.RC0/start.jar --list-config

Java Environment:
-----------------
 java.home=/home/user/java/jdk-7u21-x64/jre
 java.vm.vendor=Oracle Corporation
 java.vm.version=23.21-b01
 java.vm.name=Java HotSpot(TM) 64-Bit Server VM
 java.vm.info=mixed mode
 java.runtime.name=Java(TM) SE Runtime Environment
 java.runtime.version=1.7.0_21-b11
 java.io.tmpdir=/tmp

Jetty Environment:
-----------------
 jetty.home=/home/user/jetty-distribution-9.1.0.RC0
 jetty.base=/home/user/my-base
 jetty.version=9.1.0.RC0

JVM Arguments:
--------------
 (no jvm args specified)

System Properties:
------------------
 jetty.base = /home/user/my-base
 jetty.home = /home/user/jetty-distribution-9.1.0.RC0

Properties:
-----------
 http.timeout = 30000
 jetty.dump.start = false
 jetty.dump.stop = false
 jetty.keymanager.password = OBF:1u2u1wml1z7s1z7a1wnl1u2g
 jetty.keystore = etc/keystore
 jetty.keystore.password = OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
 jetty.port = 8080
 jetty.secure.port = 8443
 jetty.truststore = etc/keystore
 jetty.truststore.password = OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
 threads.max = 200
 threads.min = 10
 threads.timeout = 60000

Jetty Server Classpath:
-----------------------
Version Information on 11 entries in the classpath.
Note: order presented here is how they would appear on the classpath.
      changes to the --module=name command line options will be reflected here.
 0:                    3.1.0 | ${jetty.home}/lib/servlet-api-3.1.jar
 1:                  3.1.RC0 | ${jetty.home}/lib/jetty-schemas-3.1.jar
 2:                9.1.0.RC0 | ${jetty.home}/lib/jetty-http-9.1.0.RC0.jar
 3:                9.1.0.RC0 | ${jetty.home}/lib/jetty-continuation-9.1.0.RC0.jar
 4:                9.1.0.RC0 | ${jetty.home}/lib/jetty-server-9.1.0.RC0.jar
 5:                9.1.0.RC0 | ${jetty.home}/lib/jetty-xml-9.1.0.RC0.jar
 6:                9.1.0.RC0 | ${jetty.home}/lib/jetty-util-9.1.0.RC0.jar
 7:                9.1.0.RC0 | ${jetty.home}/lib/jetty-io-9.1.0.RC0.jar
 8:                9.1.0.RC0 | ${jetty.home}/lib/jetty-servlet-9.1.0.RC0.jar
 9:                9.1.0.RC0 | ${jetty.home}/lib/jetty-webapp-9.1.0.RC0.jar
10:                9.1.0.RC0 | ${jetty.home}/lib/jetty-deploy-9.1.0.RC0.jar

Jetty Active XMLs:
------------------
 ${jetty.home}/etc/jetty.xml
 ${jetty.home}/etc/jetty-http.xml
 ${jetty.home}/etc/jetty-ssl.xml
 ${jetty.home}/etc/jetty-deploy.xml

现在启动Jetty:

[my-base]$ java -jar /home/user/jetty-distribution-9.1.0.RC0/start.jar
2013-10-08 07:06:55.837:INFO:oejs.Server:main: jetty-9.1.0.RC0
2013-10-08 07:06:55.853:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:/home/joakim/my-base/webapps/] at interval 1
2013-10-08 07:06:55.872:INFO:oejs.ServerConnector:main: Started [email protected]{HTTP/1.1}{0.0.0.0:8080}

回顾配置

下面重新回顾上面的配置。

${jetty.base}和${jetty.home}

首先注意${jetty.base}和${jetty.home}的划分。

1)${jetty.home}是你的发布位于的路径,未改变的,为编辑的;

2)${jetty.base}是你的定制位于的路径。

模块

注意你配置的--module=<name>,你打包模块(库、配置XML和属性)进入一个单个的单元,包括依赖。

你能查看模块的列表:

[my-base]$ java -jar /home/user/jetty-distribution-9.1.0.RC0/start.jar --list-modules

Jetty All Available Modules:
----------------------------

Module: annotations
      LIB: lib/jetty-annotations-${jetty.version}.jar
      LIB: lib/annotations/*.jar
      XML: etc/jetty-annotations.xml
  depends: [plus]

Module: client
      LIB: lib/jetty-client-${jetty.version}.jar
  depends: []

Module: debug
      XML: etc/jetty-debug.xml
  depends: [server]

Module: deploy
      LIB: lib/jetty-deploy-${jetty.version}.jar
      XML: etc/jetty-deploy.xml
  depends: [webapp]
  enabled: ${jetty.base}/start.ini

Module: ext
      LIB: lib/ext/*.jar
  depends: []

Module: http
      XML: etc/jetty-http.xml
  depends: [server]
  enabled: ${jetty.base}/start.ini

Module: https
      XML: etc/jetty-https.xml
  depends: [ssl]

Module: ipaccess
      XML: etc/jetty-ipaccess.xml
  depends: [server]

Module: jaas
      LIB: lib/jetty-jaas-${jetty.version}.jar
      XML: etc/jetty-jaas.xml
  depends: [server]

Module: jaspi
      LIB: lib/jetty-jaspi-${jetty.version}.jar
      LIB: lib/jaspi/*.jar
  depends: [security]

Module: jmx
      LIB: lib/jetty-jmx-${jetty.version}.jar
      XML: etc/jetty-jmx.xml
  depends: []

Module: jndi
      LIB: lib/jetty-jndi-${jetty.version}.jar
      LIB: lib/jndi/*.jar
  depends: [server]

Module: jsp
      LIB: lib/jsp/*.jar
  depends: [servlet]

Module: jvm
  depends: []

Module: logging
      XML: etc/jetty-logging.xml
  depends: []

Module: lowresources
      XML: etc/jetty-lowresources.xml
  depends: [server]

Module: monitor
      LIB: lib/jetty-monitor-${jetty.version}.jar
      XML: etc/jetty-monitor.xml
  depends: [client, server]

Module: npn
  depends: []

Module: plus
      LIB: lib/jetty-plus-${jetty.version}.jar
      XML: etc/jetty-plus.xml
  depends: [server, security, jndi]

Module: proxy
      LIB: lib/jetty-proxy-${jetty.version}.jar
      XML: etc/jetty-proxy.xml
  depends: [client, server]

Module: requestlog
      XML: etc/jetty-requestlog.xml
  depends: [server]

Module: resources
      LIB: resources
  depends: []

Module: rewrite
      LIB: lib/jetty-rewrite-${jetty.version}.jar
      XML: etc/jetty-rewrite.xml
  depends: [server]

Module: security
      LIB: lib/jetty-security-${jetty.version}.jar
  depends: [server]

Module: server
      LIB: lib/servlet-api-3.1.jar
      LIB: lib/jetty-schemas-3.1.jar
      LIB: lib/jetty-http-${jetty.version}.jar
      LIB: lib/jetty-continuation-${jetty.version}.jar
      LIB: lib/jetty-server-${jetty.version}.jar
      LIB: lib/jetty-xml-${jetty.version}.jar
      LIB: lib/jetty-util-${jetty.version}.jar
      LIB: lib/jetty-io-${jetty.version}.jar
      XML: etc/jetty.xml
  depends: []
  enabled: ${jetty.base}/start.ini

Module: servlet
      LIB: lib/jetty-servlet-${jetty.version}.jar
  depends: [server]

Module: servlets
      LIB: lib/jetty-servlets-${jetty.version}.jar
  depends: [servlet]

Module: setuid
      LIB: lib/setuid/jetty-setuid-java-1.0.1.jar
      XML: etc/jetty-setuid.xml
  depends: [server]

Module: spdy
      LIB: lib/spdy/*.jar
      XML: etc/jetty-ssl.xml
      XML: etc/jetty-spdy.xml
  depends: [ssl, npn]

Module: ssl
      XML: etc/jetty-ssl.xml
  depends: [server]
  enabled: ${jetty.base}/start.ini

Module: stats
      XML: etc/jetty-stats.xml
  depends: [server]

Module: webapp
      LIB: lib/jetty-webapp-${jetty.version}.jar
  depends: [servlet]

Module: websocket
      LIB: lib/websocket/*.jar
  depends: [annotations]

Module: xinetd
      XML: etc/jetty-xinetd.xml
  depends: [server]

Jetty Active Module Tree:
-------------------------
 + Module: server [enabled]
   + Module: http [enabled]
   + Module: servlet [transitive]
   + Module: ssl [enabled]
     + Module: webapp [transitive]
       + Module: deploy [enabled]

上面包含了模块名、使用的库、使用的XML配置、以及他们依赖的其它模块(甚至包含可选的),并且标注了模块是否激活。

你可以通过编辑${jetty.base}/start.ini来管理激活模块列表。

如果你想启动一个新模块:

[my-base] $ java -jar ../jetty-distribution-9.1.0.RC0/start.jar --add-to-start=https

这增加--module=行和相关的属性(上面提到的参数化值)到你的start.ini。

参数

接下来是参数化所有的标准配置XML。在这个例子中,所有的SSL参数都是start.ini中的属性,很少或者没有编辑XML的需要。

在${jetty.base}中覆盖${jetty.home}

最后,你能在${jetty.base}中覆盖你在${jetty.home}中看到的任何东西,即使XML配置和库。

在《启动Jetty》中将有更详细的论述。

在Jetty 9.1中配置SSL总结

1)下载并解压Jetty 9.1到/home/user/jetty-distribution-9.1.0.RC1;

2)不使用了编辑该发布,到你的base文件夹;

[my-base]$ java -jar /home/user/jetty-distribution-9.1.0.RC1/start.jar

------Jetty 9.1发布提供了XML配置文件,在这里是jetty-http.xml和jetty-ssl.xml。你能在${jetty.home}/etc/中找到他们。

------我们在那些XML中参数化所有的配置项。你现在能用简单的属性来设置这些值,或者在命令行中,或者在${jetty.base}/start.ini中。

------当你激活HTTP和HTTPS模块时,Jetty自动添加对应的库和XML到Jetty。除非你有高级别的自定义设置(例如监听两个不同的端口,用SSL在每一个上面,每个都有自己的keystore和配置),你应该不需要修改XML文件。

3)用模块配置HTTPS:

------http -> server

------https -> ssl -> server

你能在${jetty.home}/modules/中找到模块的细节。为SSL包括modules/http.mod、modules/https.mod、modules/ssl.mod和modules/server.mod。

理论上,这些细节对你是不重要的。重要的是你想使用HTTPS,并且想配置它。你通过添加--module=https到你的start.ini来达到。默认情况下,模块系统是完整的,且包括所有的依赖模块。

不需要启动Jetty,在所有的模块被解析后,你可以查看配置,通过:

[my-base] $ java -jar ../jetty-distribution-9.1.0.RC0/start.jar --list-config

注意JAR包在磁盘中,并不意味着他们被使用,他们的使用通过配置项控制。

用--list-config来查看配置。注意仅发布版本中的JAR的子集被使用,你激活的模块决定这个子集。

[my-base]$ java -jar ~/jetty-distribution-9.1.0.RC0/start.jar --list-config

认证

Jetty server内的web应用(或上下文)的安全涉及两个方面:

1)认证:web应用能通过一个机制配置确定用户标识,这通过标准声明、Jetty提供的机制和这节将讲到的配置方式共同配置。

2)授权:一旦用户的标识被确认(或否决),web应用能通过带有安全限制的标准描述符配置用户能够访问哪些资源。

配置一个认证机制

Jetty server支持集中标准的认证机制:BASIC;DIGEST;FORM;CLIENT-CERT;以及其他能被插入到使用可扩展的JASPI或者SPNEGO机制的机制。

内在地,配置一个认证机制是通过设置一个Authenticator接口的实例到上下文的SecurityHandler来实现的,但大部分实例都是是通过在web.xml中设置< login-config>元素或者使用注解来实现的。

下面是一个例子,来自jetty-test-webapp web.xml(http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml?h=release-9),配置BASIC认证:

<login-config>
  <auth-method>BASIC</auth-method>
  <realm-name>Test Realm</realm-name>
</login-config>

jetty-test-webapp web.xml也包括注释掉的DIGEST和FORM配置的例子:

<login-config>
  <auth-method>FORM</auth-method>
  <realm-name>Test Realm</realm-name>
  <form-login-config>
     <form-login-page>/logon.html?param=test</form-login-page>
     <form-error-page>/logonError.html?param=test</form-error-page>
  </form-login-config>
</login-config>

使用FORM认证,你也必须配置产生一个登录表格和处理错误的页面的URL。下面简单的HTML表格来自test webapp logon.html(http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/tests/test-webapps/test-jetty-webapp/src/main/webapp/logon.html?h=release-9):

<HTML>
<H1>FORM Authentication demo</H1>
<form method="POST" action="j_security_check">
<table border="0" cellspacing="2" cellpadding="1">
<tr>
  <td>Username:</td>
  <td><input size="12" value="" name="j_username" maxlength="25" type="text"></td>
</tr>
<tr>
  <td>Password:</td>
  <td><input size="12" value="" name="j_password" maxlength="25" type="password"></td>
</tr>
<tr>
  <td colspan="2" align="center">
    <input name="submit" type="submit" value="Login">
  </td>
</tr>
</table>
</form>
</HTML>

认证机制为上下文/web应用定义服务端怎么从客户端获取认证证书,但是它不定义服务端怎么检查这些证书是否有效。为了检查证书,server和/或上下文也需要配置LoginService实例,可以通过域名匹配。

安全域

安全域用于防止你的web应用被未认证的进入。保护基于认证(表示谁正在请求进入webapp)和进入控制(限制什么能被访问和怎么访问)。

webapp在web.xml中静态地配置它的安全要求。认证通过<login-config>元素控制。访问控制通过<security-constraint>和<security-role-ref>元素指定。当一个请求请求一个受保护的资源时,web容器检查用户是否被认证,并且用户所在的角色是否有该资源的访问权限。

Servlet指导手册没有指定在WEB-INF/web.xml中的静态安全信息怎么被匹配到容器的运行时环境。在Jetty中,LoginService履行这个职责。

LoginService有一个唯一name,并且允许访问用户列表。每个用户都有认证信息(例如:密码)和与之关联的角色列表。

你可以根据需要配置一个或者多个不同的LoginService。单一的域将表明你希望你的所有web应用共享安全信息。不同的域允许你在不同的webapp将划分安全信息。

当一个请求请求认证和授权时,Jetty将用web.xml中的<login-config>元素内的<realm-name>子元素履行对LoginService的一次精确匹配。

安全域范围

一个LoginService有一个唯一名称,由一个用户列表组成。每个用户有认证信息(例如:密码)和与之关联的角色列表。你能根据你的需要配置一个或多个不同的域:

1)配置一个单个的LoginService,你的所有web应用共享安全信息。

2)配置不同的LoginService,为webapp划分不同的安全信息。

全局范围

如果你定义LoginService在Jetty配置文件中,例如${jetty.home}/etc/jetty.xml,那么它在一个Server实例上对所有的web应用都是有效的。下面是一个例子,定义一个in-memory类型的LoginService,叫做HashLoginService:

<Configure id="Server" class="org.eclipse.jetty.server.Server">
  <Call name="addBean">
    <Arg>
      <New class="org.eclipse.jetty.security.HashLoginService">
        <Set name="name">Test Realm</Set>
        <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
        <Set name="refreshInterval">0</Set>
      </New>
    </Arg>
  </Call>
</Configure>

如果你在一个Server上定义超过一个LoginService,你将需要为每一个上下文指定你想使用哪一个。你可以告诉上下文LoginService的名称,或者传递它给LoginService实例。最下面是一个例子:

<Configure class="org.eclipse.jetty.webapp.WebAppContext">
 <Get name="securityHandler">
   <!-- Either: -->
   <Set name="loginService">
     <New class="org.eclipse.jetty.security.HashLoginService">
           <Set name="name">Test Realm</Set>
     </New>
   </Set>

   <!-- or if you defined a LoginService called "Test Realm" in jetty.xml : -->
   <Set name="realmName">Test Realm</Set>

 </Get>

每webapp范围

你也可以为单独的web应用定义LoginService。下面是怎么为上下文定义同样的HashLoginService:

<Configure class="org.eclipse.jetty.webapp.WebAppContext">
  <Set name="contextPath">/test</Set>
  <Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/test</Set>
  <Get name="securityHandler">
    <Set name="loginService">
      <New class="org.eclipse.jetty.security.HashLoginService">
            <Set name="name">Test Realm</Set>
            <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
      </New>
    </Set>
  </Get>
</Configure>

Jetty提供了一组不同的LoginService类型,下面将做介绍。

配置一个LoginService

一个LoginService实例有一个认证机制,被用于检查被认证机制收集的用户名和证书的有效性。Jetty提供了下面的LoginService的实现:

------HashLoginService

用户域是一个hash表,通过编程填充或者通过Java属性文件填充。

------JDBCLoginService

使用一个JDBC连接到一个SQL数据库进行认证。

------DataSourceLoginService

用JNDI定义认证的DataSource。

------JAASLoginService

用JAAS提供商进行验证。

------SpnegoLoginService

SPNEGO认证。

一个LoginService的实例能通过下面的方式匹配到上下文/webapp:

1)一个LoginService实例可以被直接设置到SecurityHandler实例,通过代码或者IoC XML。

2)用LoginService实例(作为依赖bean设置到Server实例中)的名称匹配定义在web.xml中的域名。

3)如果仅一个单个的LoginService实例被设置到Server,则它被用于上下文的登录service。

HashLoginService

HashLoginService是一个简单有效的登录service,用于从一个Java属性文件加载用户名、证书和角色集,属性文件格式如下;

username: password[,rolename ...]

这里:

------username

用户的唯一标识

------password

用户密码(可能被扰乱或者被MD5加密)

------rolename

用户的角色

例如:

admin: CRYPT:ad1ks..kc.1Ug,server-administrator,content-administrator,admin
other: OBF:1xmk1w261u9r1w1c1xmq
guest: guest,read-only

你使用一个名称和属性文件地址配置HashLoginService:

<Item>
<New class="org.eclipse.jetty.security.HashLoginService">
  <Set name="name">Test Realm</Set>
  <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
</New>
</Item>

你也能配置它定期检测属性文件改变,如果发生变化则重新加载它。reloadInterval的单位是秒:

<New class="org.eclipse.jetty.security.HashLoginService">
    <Set name="name">Test Realm</Set>
    <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
    <Set name="reloadInterval">5</Set>
    <Call name="start"></Call>
  </New>

JDBCLoginService

在这个实现中,认证和角色信息被存储在数据库中,通过JDBC访问。一个属性文件定义JDBC连接和数据库表信息。下面是属性文件的例子:

jdbcdriver = org.gjt.mm.mysql.Driver
url = jdbc:mysql://localhost/jetty
username = jetty
password = jetty
usertable = users
usertablekey = id
usertableuserfield = username
usertablepasswordfield = pwd
roletable = roles
roletablekey = id
roletablerolefield = role
userroletable = user_roles
userroletableuserkey = user_id
userroletablerolekey = role_id
cachetime = 300

数据库表的格式是(伪sql):

users
(
  id integer PRIMARY KEY,
  username varchar(100) NOT NULL UNIQUE KEY,
  pwd varchar(50) NOT NULL
);
user_roles
(
  user_id integer NOT NULL,
  role_id integer NOT NULL,
  UNIQUE KEY (user_id, role_id),
  INDEX(user_id)
);
roles
(
  id integer PRIMARY KEY,
  role varchar(100) NOT NULL UNIQUE KEY
);

这里:

------users为每个用户包含一个条目,包括:

------id:用户的唯一标识

------user:用户名

------pwd:用户密码(可能被扰乱或者被MD5加密)

------user-roles是一个表格,每行表示一个角色授权给一个用户:

------user_id:用户唯一标识

------role_id:用户角色

------roles是一个表格,包含系统中的所有角色

------id:角色的唯一标识

------role:角色的可读的名称

如果你想使用扰乱、MD5扰乱或者加密密码,users表的pwd列必须足够大。

你定义一个JDBCLoginService,需要指定域名和描述数据库的属性文件路径:

<New class="org.eclipse.jetty.security.JDBCLoginService">
  <Set name="name">Test JDBC Realm</Set>
  <Set name="config">etc/jdbcRealm.properties</Set>
</New>

授权

按照servlet指导文档,授权基于角色。就像我们看到过的,一个LoginService关联的一个用户对应一组角色。当一个用于请求一个受保护的资源时,LoginService将被用于认证请求的用户,然后确认用户对应的角色集中是否存在对该资源有权限的角色。

在Servlet 3.1之前,基于角色的授权能定义:

1)授权于一组命名的角色

2)访问完全禁止,无论任何角色

3)访问授权给一个对应web.xml中定义的任何角色的用户。这通过在<security-constraint>中为<auth-constraint>的<role-name>指定为"*"表明

Servlet 3.1增加了另一个授权:

1)访问授权给被认证的任何用户,无论任何角色。这通过在<security-constraint>中为<auth-constraint>的<role-name>指定值"**"来表明

限制表单内容

提交到服务端的表单内容被Jetty组织为一个参数map交给web应用处理。这个机制是容易被攻击的,客户端可以通过提交大数据量的表单内容或者大量的表单keys来消耗服务端的内容和CPU,这就是拒绝服务攻击(DOS)。因此Jetty限制能够提交到Jetty的数据和keys的数量。

Jetty允许的默认的最大值是200000 bytes和1000 keys.你能改变这个默认值为特定Server实例上的一个特定的webapp或者所有的webapp。

配置表单显示为一个webapp

为了为单个webapp配置表单限制,上下文处理器(或者webappContext)实例必须用下面的方式配置:

ContextHandler.setMaxFormContentSize(int maxSizeInBytes);
ContextHandler.setMaxFormKeys(int formKeys);   

这些方法可以在代码中直接调用,但更通常的是通过上下文XML或者WEB-INF/jetty-web.xml配置:

<Configure class="org.eclipse.jetty.webapp.WebAppContext">

...

<Set name="maxFormContentSize">200000</Set>

<Set name="maxFormKeys">200</Set>

</Configure>

配置表单限制为Server

如果一个上下文没有指定表单限制,那么将使用server的配置。下面是在jetty.xml中配置:

<configure class="org.eclipse.jetty.server.Server">

  ...

  <Call name="setAttribute">
    <Arg>org.eclipse.jetty.server.Request.maxFormContentSize</Arg>
    <Arg>100000</Arg>
   </Call>
  <Call name="setAttribute">
    <Arg>org.eclipse.jetty.server.Request.maxFormKeys</Arg>
    <Arg>2000</Arg>
   </Call>
</configure>

别名文件和符号链接(Aliased Files and Symbolic links)

web应用将经常提供静态内容。然而由于文件系统经常为同样的文件提供多个别名,导致安全限制和其他servlet URI空间映射通过别名被绕过。

比较典型的例子是在Windows文件系统下的大小写敏感和8.3文件名实现。如果一个webapp中的文件叫做/mysecretfile.txt,被安全限制保护,对应URI为/mysecretfile.txt,那么一个对/MySecretFile.TXT的请求将不匹配URI限制,因为URI是大小写敏感的,但是Windows文件系统将报告存在这个文件并且为这个请求提供服务,从而绕过安全限制。比大小写敏感更少见的是Windows文件系统也支持8.3文件名,主要是为了兼容性。因此一个对URI为/MYSECR~1.TXT的请求将不匹配安全限制,但文件系统会找到对应的文件并提供服务。

有一些别名的例子,不仅仅在windows上:

1)NTFS Alternate流命名为这样c:\test\file.txt::$DATA:name。

2)OpenVMS支持文件版本化,/mysecret.txt;N表示对应/mysecret.txt的版本N,本质上是别名。

3)clearcase软件配置管理系统提供一个文件系统,在一个文件名中的@@表示对应一个特定版本的别名。

4)unix文件系统支持/./foo.txt作为/foo.txt的别名。

5)一些JVM实现不正确的假定null字符是一个字符串的终结符,以至于一个文件名/foobar.txt%00是/foobar.txt的别名。

6)Unix符号链接和硬链接是别名的一种形式,允许同样的文件或文件夹有多个名称。

另外,不仅仅URI安全限制能被绕过。例如匹配模式*.jsp到JSP Servlet的URI映射可以被绕过,通过请求一个别名象/foobar.jsp%00,导致JSP的源代码被文件系统返回,而不是执行这个JSP。

好的安全实践

别名导致的问题,一部分是由于标准web应用安全模式是允许所有的请求除非请求被安全限制明确否定。一个安全的最佳实践是否定所有的请求,只允许那些特定标注为允许的。以这种方式设计web应用安全限制是可能的,但在所有的场景下这样做是困难的,因此它不是默认的。因此探测和否定对别名静态内容的请求对Jetty来说是重要的。

别名探测

要Jetty知道被文件系统实现的所有别名是不可能的,因此它不会尝试去做已知的别名检查。取而代之Jetty通过用一个文件的标准路径来探测别名。如果一个被Jetty处理的文件资源有一个标准名,不同于请求这个资源的名称,那么Jetty确定这是一个资源的别名请求,它将被返回通过ServletContext.getResource(String)方法(或类似的),而不是作为静态资源服务。

如果Jetty正运行在一个windows操作系统上,那么一个叫/MySecret.TXT的文件将有一个精确匹配的标准名。于是当对/mysecret.txt或者/MYSECR~1.TXT的请求到达时,由于和标准名不匹配,这些请求被认为是对别名的请求,他们将不被作为静态资源服务,最终能够一个404响应返回。

服务别名和符号链接

不是所有的别名都是坏的,或者被认为尝试破坏安全限制的。当组合复杂的web应用时,符号链接是很有用的,然而默认Jetty将不服务他们。因此Jetty上下文支持一个可扩展的AliasCheck机制,为了允许别名资源被作为有条件的服务。在这个方面,“好”别名能被探测并且服务。Jetty提供了几种AliasCheck接口的通用的实现,作为ContextHandler的内嵌类:

------ApproveAliases

接收所有别名(使用需谨慎!)

------AllowSymLinkAliasChecker

使用java-7 Files.readSymbolicLink(path) and Path.toRealPath(...) APIs检查别名,通过的作为有效的符号链接。

一个应用可以自由的实现它自己的别名检查。别名检查能通过上下文部署文件或者WEB-INF/jetty-web.xml安装:

<!-- Allow symbolic links  -->
<Call name="addAliasCheck">
  <Arg><New class="org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker"/></Arg>
</Call>

安全密码扰乱

有很多地方你可能想使用和存储密码,例如为SSL链接器和域中的用户密码。

密码能被存储在明文、被扰乱的、被检验和的和被加密的,为了增加安全性。为了密码安全,方法的选择依赖于你正在什么地方使用密码。在许多场景下,例如keystore密码和摘要式身份验证,系统必须重新得到原始密码,这需要用到扰乱方法。扰乱算法的缺陷是它仅保护密码免于随意查看。

当存储的密码同用户输入的进行比较时,代码能对用户输入应用和保护存储密码同样的算法,然后比较结果,使密码认证更加安全。

类org.eclipse.jetty.http.security.Password能被用于产生所有密码的变化。

不带参数执行可以看到使用指导:

$ export JETTY_VERSION=9.0.0-SNAPSHOT
$ java -cp lib/jetty-util-$JETTY_VERSION.jar org.eclipse.jetty.util.security.Password

Usage - java org.eclipse.jetty.util.security.Password [<user>] <password>
If the password is ?, the user will be prompted for the password

例如,为了产生一个安全的密码版本,假定用户"me",密码"blah",则:

$ export JETTY_VERSION=9.0.0.RC0
$ java -cp lib/jetty-util-$JETTY_VERSION.jar org.eclipse.jetty.util.security.Password me blah
blah
OBF:20771x1b206z
MD5:639bae9ac6b3e1a84cebb7b403297b79
CRYPT:me/ks90E221EY

你现在能剪切,然后粘贴你选择的安全版本进入你的配置文件或者java代码。

例如,下面的最后一行展示了你怎么将上面产生的加密后的密码剪切并粘贴到你的属性文件中,供LoginService使用:

admin: CRYPT:ad1ks..kc.1Ug,server-administrator,content-administrator,admin
other: OBF:1xmk1w261u9r1w1c1xmq
guest: guest,read-only
me:CRYPT:me/ks90E221EY

注意:不要忘记拷贝OBF:、MD5:或者CRYPT:前缀,否则Jetty将无法正确使用。

你也能用在Jetty xml文件中使用扰乱的密码。下面是一个例子,为JDBC DataSource设置扰乱的密码:

<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
   <Arg></Arg>
   <Arg>jdbc/DSTest</Arg>
   <Arg>
     <New class="com.jolbox.bonecp.BoneCPDataSource">
       <Set name="driverClass">com.mysql.jdbc.Driver</Set>
       <Set name="jdbcUrl">jdbc:mysql://localhost:3306/foo</Set>
       <Set name="username">dbuser</Set>
       <Set name="password">
          <Call class="org.eclipse.jetty.util.security.Password" name="deobfuscate">
                <Arg>OBF:1ri71v1r1v2n1ri71shq1ri71shs1ri71v1r1v2n1ri7</Arg>
          </Call>
       </Set>
       <Set name="minConnectionsPerPartition">5</Set>
       <Set name="maxConnectionsPerPartition">50</Set>
       <Set name="acquireIncrement">5</Set>
       <Set name="idleConnectionTestPeriod">30</Set>
    </New>
  </Arg>
</New>

JAAS支持

后续补充

Spnego支持

后续补充

Jetty:配置安全,布布扣,bubuko.com

时间: 2024-10-26 17:13:27

Jetty:配置安全的相关文章

IntelliJ IDEA使用(二):tomcat和jetty配置

上一讲用idea创建了maven web项目,接下来我们把项目发布到tomcat和jetty运行,以便进一步地开发和调试 配置tomcat 第一.打开菜单栏 第二.点击设置按钮,添加应用服务器,选择tomcat server 选择tomcat目录 添加后如下所示 到此我们已经把tomcat服务器添加进idea了,接下来还得设置maven web项目的部署信息 第三.设置部署文件 ctrl + shift + alt + s 快捷键打开Project Structure 设置Modules: 检查

阿里云服务器Linux CentOS安装配置(五)jetty配置、部署

阿里云服务器Linux CentOS安装配置(五)jetty配置.部署 1.官网下载jetty:wget http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-distribution/9.2.17.v20160517/jetty-distribution-9.2.17.v20160517.zip 我用上面的命令下载速度太慢了,于是先下载到本地,再传到服务器的 2.解压:unzip jetty-distribution-9.2.17.v201

jetty配置solr

1.到jetty官方网站下载jetty8 2.解压文件 把solr4.8目录中的solr目录(索引文件及配置)拷贝到jetty8根目录 3.把solr4.8/webapps下的solr.war解压  然后把解压后的目录solr拷贝到  jetty8/webapps目录下 此目录下的.war文件可以都删除 4.在jetty/context下创建solr.xml文件(其它.xml文件可以删除) 文件内容如下: <?xml version="1.0" encoding="IS

Jetty实战之 嵌入式运行Jetty 配置Https

在开发Java web项目时候,可以在项目中嵌入Jetty服务的方式来运行web程序. 嵌入式Jetty服务比较简洁,不用在服务器再部署其他服务. 本人用的Jetty9.3,其他版本的应该也差不多,我见过别人的嵌入式Jetty服务,他们都是把一些配置参数写死在代码里,不利于维护,我是做了进一步的改进,把配置参数放在配置文件,然后直接把配置参数读到相应的类里. 首先列一下Jetty项目里比较重要的xml:jetty-https.xml,jetty-ssl.xml,jetty-ssl-context

Spring Boot – Jetty配置

前言 默认情况下,Spring Boot会使用内置的tomcat容器去运行应用程序,但偶尔我们也会考虑使用Jetty去替代Tomcat: 对于Tomcat和Jetty,Spring Boot分别提供了对应的starter,以便尽可能的简化我们的开发过程: 当我们想使用Jetty的时候,可以参考以下步骤来使用. 添加spring-boot-starter-jetty依赖 我们需要更新pom.xml文件,添加spring-boot-starter-jetty依赖,同时我们需要排除spring-boo

Jetty配置虚拟目录,实现把web项目发布到自定义目录,指定指定上下文访问;jetty编码修改

2019-12-31     17:28:38 一般只需要把Java站点文件夹或*.war文件拷贝到Web Server的webapps文件夹下,即可启动运行该站点,但更多时候,我们并不想拷贝站点,而是希望Web在Server文件夹之外运行,这时就需要配置虚拟目录了.不同的WebServer配置虚拟目录的方式不太一样,这里的配置方法仅针对Tomcat和Jetty. 1.Tomcat:找到并打开Tomcat目录下的conf/server.xml文件,在Host小节中添加以下配置即可: <Conte

maven插件jetty配置

<plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>9.2.3.v20140905</version> <configuration> <stopPort>9966</stopPort> <stopKey>stop</stop

maven jetty配置

etty 是一个用 Java 实现.开源.基于标准的,并且具有丰富功能的 Http 服务器和 Web 容器,可以免费的用于商业行为.Jetty 这个项目成立于 1995 年,现在已经有非常多的成功产品基于 Jetty,比如 Apache Geromino, JBoss, IBM Tivoli, Cisco SESM 等.Jetty 可以用来作为一个传统的 Web 服务器,也可以作为一个动态的内容服务器,并且 Jetty 可以非常容易的嵌入到 Java 应用程序当中. 在按照这个网址http://

Jetty的安装和配置

Jetty 是一个开源的servlet容器,它为基于Java的web内容,例如JSP和servlet提供运行环境.Jetty是使用Java语言编写的,它的API以一组JAR包的形式发布.开发人员可以将Jetty容器实例化成一个对象,可以迅速为一些独立运行(stand-alone)的Java应用提供网络和web连接.(Jetty是一个开源的软件,可以作为HTTP服务,javax.servlet的容器.) 配置jetty server的步骤: 创建server 配置connector 配置handl

Jetty学习二:配置概览-怎么配置Jetty

Jetty POJO配置 Jetty的核心组件是Plain Old Java Objects(POJOs):配置Jetty的大部分工作就是在Jetty POJOs上的初始化.装配和设置域的处理,你能通过以下的方式来实现:  1)直接通过Java代码初始化和装配Jetty对象.这个在后面Embedding Jetty讲. 2)用Jetty XML配置(一个控制反转(IoC)框架)初始化和装配Jetty对象.etc/jetty.xml文件是基本的Jetty XML配置文件,但有一些其它的etc/je