2010-02-10 29 views
19

目前,只要客戶端使用Web瀏覽器訪問網站,我就已經成功地實現了相互驗證安全性,因爲瀏覽器會爲您處理所有證書交換。現在我需要創建一個安全接口,用戶可以使用該接口通過HTTPS訪問Web服務,並使用服務器所需的相互身份驗證。與Web服務相互驗證

首先,有沒有任何資源可以幫助我呢?我尋找了相當一段時間,什麼都沒發現。任何人都可以給我如何去做這個提示?其次,我認爲我最大的障礙是我缺乏對如何處理證書的理解。我該如何協商接受服務器密鑰並將自己的密鑰呈現給服務器?這是用Java編寫的。

回答

1

一個簡單的配方在this blog entry中給出。

但我認爲真正的答案可能取決於您使用什麼Java API來實現您的客戶端HTTP交互。例如,它看起來像你會使用JAX-RPC做a bit differently

6

如果Web服務庫使用標準java.net.URL類作爲HTTP客戶端,則可以設置一些system properties,雙向認證將由內置HTTPS支持處理。

necessary properties是:

  • javax.net.ssl.trustStore:包含根CA證書
  • javax.net.ssl.keyStore:包含客戶證書和私鑰
  • javax.net.ssl.keyStorePassword:密碼保護客戶端的私鑰

這些設置成爲進程所有SSL連接的默認設置。如果你想更好的控制,你必須建立你自己的SSLContext。您的webservice運行時是否可能取決於您選擇的運行時間。

11

對於SSL(又名雙向SSL)在瀏覽器之外的相互認證,你需要......嗯,其實,讓我們看看你需要什麼單向SSL第一:

  1. 一服務器密鑰庫
  2. 客戶端信任庫

服務器密鑰庫包含服務器(可能是自簽名)證書和私鑰。該存儲由服務器用於簽署消息並向客戶端返回憑證。

客戶端信任庫包含服務器的(自簽名)證書(從服務器密鑰庫提取到獨立證書中,沒有服務器私鑰)。如果證書未由信任的CA簽名,那麼您已在與JRE捆綁在一起的truststore中擁有證書。這一步可以創建一個信任鏈。

有了這個,您可以實現單向SSL(傳統用例)。

要實現雙向SSL,你需要這個設置的「對稱」,所以我們需要添加:

  1. 客戶端密鑰庫
  2. 服務器信任

的客戶端密鑰庫包含客戶端(可能是自簽名的)證書和私鑰。該存儲由客戶用於與服務器密鑰庫相同的目的,即在TLS相互認證握手期間將客戶證書發送到服務器。

服務器信任庫包含客戶端(自簽名)獨立證書(從客戶端密鑰庫中提取到獨立證書中,不包含客戶端私鑰)。這與前面提到的完全相同的原因是必需的。

一些資源,幫助您生成所有這些東西,並實現最終的解決方案:

+3

雖然你已經解釋了相互認證的概念相當不錯,鏈接是不是非常有幫助的。自2006年以來,Java Web服務安全性發生了一些變化! :) – Catchwa 2010-06-29 04:54:50

14

我花了很長在這個時候,但我終於找到了一個實例盟友的作品。它基於Glassfish和Netbeans,但我想你可以在其他環境(如Eclipse和Tomcat)中使用它,如果你玩過它的話。

http://java.sun.com/webservices/reference/tutorials/wsit/doc/WSIT_Security9.html#wp162511

我雖然發現的問題是,當你想用自己的證書,而不是隨之而來的GlassFish預裝的人。

注意:我不是安全專家。不要將其部署到生產環境!

要做到這一點,我使用NetBeans 6.9,JDK 1.6,GlassFish的3.0.1和OpenSSL V1.0(我使用的是非官方Win32的二進制文件)

# Create the CA 
mkdir ca server client 
cd ca 
openssl req -new -x509 -days 3650 -extensions v3_ca -keyout ca.key -out ca.pem 
echo 02 > serial.txt 
cd .. 

# Creating the Server Keystore 

openssl req -days 3650 -newkey rsa:1024 -keyout server/server.key -out server/server.req 
openssl x509 -extensions usr_cert -extfile C:\testbed\OpenSSL-Win32\bin\openssl.cfg -CA ca/ca.pem -CAkey ca/ca.key -CAserial ca/serial.txt -req -in server/server.req -out server/server.crt 
openssl pkcs12 -export -inkey server/server.key -in server/server.crt -out server/server.p12 -name server 
keytool -importkeystore -destkeystore server/server.jks -deststoretype jks -srckeystore server/server.p12 -srcstoretype pkcs12 
keytool -exportcert -alias server -keystore server/server.jks -file server/server.cer 

# Create the Client Keystore 

openssl req -days 3650 -newkey rsa:1024 -keyout client/client1.key -out client/client1.req 
openssl x509 -extensions usr_cert -extfile C:\testbed\OpenSSL-Win32\bin\openssl.cfg -CA ca/ca.pem -CAkey ca/ca.key -CAserial ca/serial.txt -req -in client/client1.req -out client/client1.crt 
openssl pkcs12 -export -inkey client/client1.key -in client/client1.crt -out client/client1.p12 -name client1 
keytool -importkeystore -destkeystore client/client1.jks -deststoretype jks -srckeystore client/client1.p12 -srcstoretype pkcs12 
keytool -exportcert -alias client1 -keystore client/client1.jks -file client/client1.cer 

# Import public keys and certificates into each others keystores 

keytool -import -noprompt -trustcacerts -alias client1 -file client/client1.cer -keystore server/server.jks 
keytool -import -noprompt -trustcacerts -alias server -file server/server.cer -keystore client/client1.jks 
keytool -import -noprompt -trustcacerts -alias my_ca -file ca/ca.pem -keystore server/server.jks 
keytool -import -noprompt -trustcacerts -alias my_ca -file ca/ca.pem -keystore client/client1.jks 
keytool -import -noprompt -trustcacerts -alias my_ca -file ca/ca.pem -keystore "C:\Program Files\glassfish-3.0.1\glassfish\domains\domain1\config\cacerts.jks" 
keytool -import -noprompt -trustcacerts -alias my_ca -file ca/ca.pem -keystore "C:\Program Files\Java\jdk1.6\jre\lib\security\cacerts" 
move "C:\Program Files\glassfish-3.0.1\glassfish\domains\domain1\config\keystore.jks" "C:\Program Files\glassfish-3.0.1\glassfish\domains\domain1\config\keystore.jks.backup" 
copy server\server.jks "C:\Program Files\glassfish-3.0.1\glassfish\domains\domain1\config\keystore.jks" 

在GlassFish管理控制檯,啓用HTTP監聽器的安全性,勾選SSL3,TLS和客戶端身份驗證框,將證書NickName設置爲服務器,將密鑰庫設置爲config \ keystore.jks,將信任庫設置爲config \ keystore.jks,將信任算法設置爲PKIX並將最大證書長度保留爲5.

在NetBeans中,創建一個新的Web應用程序項目。其中,創建一個新的Web服務。

我的web服務代碼是這樣的:

@WebService() 
public class ListProducts { 

    @Resource WebServiceContext context; 

    @WebMethod(operationName = "listProducts") 
    public String listProducts() { 
    return context.getUserPrincipal().toString(); 
    } 

} 

右鍵單擊Web服務,然後選擇編輯Web服務屬性。勾選安全服務框並選擇相互證書安全性作爲安全機制。點擊Configure ...按鈕,並勾選Encrypt Signature框。現在取消Use Use Defaults框,然後點擊Keystore按鈕。設置server.jks密鑰庫的位置並選擇server別名。對Truststore配置執行相同操作(儘管您不必在此選擇別名)。

將client1.p12客戶端證書導入瀏覽器。將Web服務部署到Glassfish。在瀏覽器中打開Web服務,並通過HTTPS瀏覽已部署的WSDL。下載WSDL和任何其他模式。將任何引用的模式重命名爲本地副本,以便在使用WSDL2Java時,NetBeans不會使用任何遠程資源。 (這一段是因爲您已將WSDL限制爲具有批准證書的客戶端,但NetBeans無法遠程獲取它,因爲它無法訪問有問題的證書)。

創建一個新的Java項目。創建一個新的Web服務客戶端。出現提示時,將NetBeans指向保存的WSDL文件。導入METRO2.0庫文件(C:\Program Files\Netbeans 6.9\enterprise\modules\ext\metr\webservices-*.jar)。我的代碼是這樣的:

public static void main(String[] args) { 
    System.getProperties().put("javax.net.ssl.keyStore", "C:\\NetBeansProjects\\security-04\\ssl\\client\\client1.jks"); 
    System.getProperties().put("javax.net.ssl.keyStorePassword", "changeit"); 
    System.getProperties().put("javax.net.ssl.trustStore", "C:\\NetBeansProjects\\security-04\\ssl\\client\\client1.jks"); 
    System.getProperties().put("javax.net.ssl.trustStorePassword", "changeit"); 
    System.out.println(new ListProductsService().getListProductsPort().listProducts()); 
} 

複製web服務-api.jar文件到您的Java \ JDK1.6 \ JRE \ LIB \ endorsed目錄。 右鍵單擊Web服務引用並選擇編輯Web服務屬性。將密鑰庫位置設置爲client1.jks,並將別名設置爲client1。將信任庫位置設置爲client1.jks,並將別名設置爲server

希望你現在可以運行你的客戶,你應該看到像這樣的輸出: [email protected], CN=Bob Smith, OU=Something, O=SomethingElse, L=AnyTown, ST=AnyState, C=US