使用WebService發布soap接口,並實現客戶端的https驗證


什么是https

HTTPS其實是有兩部分組成:HTTP + SSL / TLS,

也就是在HTTP上又加了一層處理加密信息的模塊,並且會進行身份的驗證。

如何進行身份驗證?

首先我們要明白什么是對稱加密,什么是非堆成加密

對稱加密

對稱加密就是只有一個密鑰,客戶端雙方按照約定的密鑰對自己的明文進行加密。

但是這種方式有個很不好的情況。A和B通訊之前並不知道使用哪種密鑰加密。所以在第一次通訊的時候會事先溝通好。

A->B:嗨!在嗎?我們開始聊天吧。
B->A:好的,我們的密鑰是:xxxxx。

如果此時黑客截取到了你的密鑰,那加密也無濟於事。

非對稱加密

非對稱加密就是在對稱加密上再套一層公鑰。所以有公鑰和私鑰兩種形式。

A->B:嗨!在嗎?我們開始聊天吧。
B->A:好的,我們的公鑰是:xx。
A->B(以公鑰:xx加密): 你好我是A,我們之后使用對稱加密的zz來通訊。
B:以xx的密鑰解密,得到密鑰zz,之后雙方通訊都通過對稱加密的zz來通訊。

公鑰是公開的,用公鑰加密的信息只能使用密鑰解密。公鑰是解不開的,即便公鑰被非法路由或黑客攔截,也不能通過公鑰解密。這就是數學的魅力,有興趣的話可以了解一下:RSA算法

這樣就安全了?答案是否定的,如果在B->A發送公鑰 xx 的時候就已經被非法路由器或者黑客攔截,然后向A發送偷天換日后的公鑰 yy。此時非法路由就有兩個公鑰 xxyy 。並且擁有有 yy 的私鑰,因為 yy 是其自己生成的。

因此,當A收到非法路由發送過來的偷天換日后的公鑰 yy ,A信以為真的認為這個就是B發送過來的公鑰。當A向B發送發送一串由 YY 公鑰加密的信息,非法路將其攔截並且用 yy 的密鑰解密后再通過公鑰 xx 加密后發送給B。這樣你的消息通訊依舊是不安全的。

證書體系

上面這個環節按理來說已經很安全了,為什么還是會被黑客或者非法路由攻擊?思考上面的環節,問題出在發送公鑰的時候,被黑客攔截,然后偷天換日的換了一個公鑰。那是不是只要保證公鑰的不可更改,就能維護了呢?是的,證書的出現就是解決這個問題(也是為什么你要去找證書簽發機構花錢購買證書的原因)!!

簡單來說,一個HTTPS網站響應給我們的並不是一個公鑰,而是證書。證書上包含了公鑰,還包含了域名、簽發機構、有效期、簽名等等。

那證書的安全性怎么保證?為什么中間人不能做一個假證書?

因為這套證書體系已經根植於每一個操作系統里了。每一個操作系統里,都內置了數十張根證書,每個根證書都對應一個非常權威的證書簽發機構。這些根證書上記錄了各個機構的公鑰。

那非法路由或者黑客能不能申請一個真的證書然后去做劫持呢?

通常來說,證書簽發機構的審核非常嚴格,如果無法證明B這個域名屬於他,簽發機構是不會給他簽發一個知乎域名的證書的。而如果中間人用了其他域名的證書,瀏覽器會發現你請求的域名和返回的證書不一致,從而拒絕繼續請求。除非你一定要點下面的「仍然繼續」:

最后無奈地說,在破解了這么多數學上的難題后,HTTPS的安全性仍然保證在『證書簽發機構一定都是很有良心的』這種脆弱的基礎上。(即便一些網站是通過證書簽發機構的,但是嘛依舊會被植入小廣告,咳咳....)。

實現客戶端驗證的WebService

我們了解了https和證書的作用。其實我們在系統之間內部通訊的時候就可以使用對稱加密的方式進行訪問即可。

因為是內部嘛,我們提前約定好使用何種證書就可以了。除非是很正式的項目,否則使用自己簽發的證書即可,因為官方生成證書是要花錢滴。

有兩種方式

第一種:服務端生成一個證書,每個客戶端都生成自己的證書,然后讓服務端與各個客戶端相互信任。

第二種:生成一個證書,將這個證書派發給各個客戶端,每個客戶端攜帶該證書就會被服務端認證(這種安全性稍微低一些,但是在大部分對安全性要求不是特別高的場景推薦使用。下面主要說明這一種方式,如果想實現第一種參考:https://blog.csdn.net/u011350541/article/details/71941536

生成證書

首先保證服務器有jdk,打開CMD工具,進入到jdk的bin目錄下輸入一下信息。如果配置了環境變量則直接在命令行中輸入即可。

keytool -genkey -alias tomcat -keypass 123456 -keyalg RSA -keysize 1024 -validity 365 -keystore D:/keys/server.jks -storepass 123456

上述參數的具體說明如下:

keytool 

-genkey 

-alias service(別名) 

-keypass 123456(別名密碼) 

-keyalg RSA(算法) 

-keysize 1024(密鑰長度) 

-validity 365(有效期,天單位) 

-keystore D:/keys/server.jks(指定生成證書的位置和證書名稱) 

-storepass 123456(獲取jks信息的密碼)

發布的soap接口

    /**
     * @author Eric
     * @Title: SoapService
     * @date 2019/7/17 10:42
     * @Description: 發布的soap接口,注意注釋的使用
     */
    @WebService
    public interface SoapService {
        void sayHello(@WebParam(name = "clientName") String clientName);
    }
    

接口的具體實現類

/**
 * @author Eric
 * @Title: SoapServiceImpl
 * @date 2019/7/17 10:42
 * @Description: soap接口的具體實現,注意注釋的使用
 */
@javax.jws.WebService
public class SoapServiceImpl implements SoapService {
    @Override
    public void sayHello(String clientName) {
        System.out.println(clientName + "調用接口打了招呼");
    }
}

發布soap接口

/**
 * @author Eric
 * @Title: testTest
 * @date 2019/7/17 10:45
 * @Description: 發布soap接口
 */
public class Release {

    public static void main(String[] args) throws Exception {
        initSoap();
    }
    
    //初始化soap接口
    public static void initSoap() {
        try {
            String host = "0.0.0.0";
            int port = 8888;
            String address = "https://" + host + ":" + port + "/logProcessor"; //發布於https
            JaxWsServerFactoryBean sf = new JaxWsServerFactoryBean();
            sf.setServiceClass(SoapService.class); //發布實現soap的接口類(你自己實現的接口,里面的方法就是發布的soap接口)
            sf.setAddress(address);
            SoapServiceImpl soapServiceImpl = new SoapServiceImpl(); //SoapService的實現類
            sf.getServiceFactory().setInvoker(new BeanInvoker(soapServiceImpl));
            sf = configureSSLOnTheServer(sf, port);
            Server server = sf.create();
            String endpoint = server.getEndpoint().getEndpointInfo().getAddress();
            System.out.println("soap發布的地址為:" + endpoint);
        } catch (Exception e) {
                System.out.println("Soap初始化失敗:"+e);
        }
        
    }
    
    //https並且開啟客戶端認證。如果發布的接口是http,則無需實現該方法。
    private static JaxWsServerFactoryBean configureSSLOnTheServer(JaxWsServerFactoryBean sf, int port) throws Exception {
        TLSServerParameters tlsParams = new TLSServerParameters();
        ClientAuthentication clientAuthentication = new ClientAuthentication();

        clientAuthentication.setRequired(true); //開啟客戶端認證
        tlsParams.setClientAuthentication(clientAuthentication);
        KeyStore keyStore = KeyStore.getInstance("JKS");
        String password = "123456"; //生成證書時候定義的的密碼
        File truststore = new File(Paths.get("D:\\keys", "server.jks").toString());
        keyStore.load(new FileInputStream(truststore), password.toCharArray());
        KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyFactory.init(keyStore, password.toCharArray());
        KeyManager[] km = keyFactory.getKeyManagers();
        tlsParams.setKeyManagers(km);

        truststore = new File(Paths.get("D:\\keys", "server.jks").toString());
        keyStore.load(new FileInputStream(truststore), password.toCharArray());
        TrustManagerFactory trustFactory = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustFactory.init(keyStore);
        TrustManager[] tm = trustFactory.getTrustManagers();
        tlsParams.setTrustManagers(tm);

        JettyHTTPServerEngineFactory factory = new JettyHTTPServerEngineFactory();
        factory.setTLSServerParametersForPort(port, tlsParams);
     
    }
}

使用soapUI模擬客戶端調用soap接口

通過上述代碼,我們將接口發布在了你自己定義的https://0.0.0.0:8888/logProcessor。如果發布成功,我們想遠程調用soap接口,此時打開soapUI

  1. 選擇左上角File然后選擇Preferences。
    image
  2. 選擇SSL Settings,在KeyStore上導入我們生成的證書。否則無法遠程調用(因為我們在代碼中開啟了客戶端認證,如果沒有開啟可以跳過這一步
    image
  3. 然后返回主界面,創建soap,在彈出的界面中 ‘Project Name’可以自己定義。‘Initial WSDL’中輸入你發布的地址加上‘?wsdl’如下:https://0.0.0.0:8888/logProcessor?wsdl
    image
  4. 如果創建成功,你就能在左邊看到自己項目中發布的接口。選擇我們發布的接口sayHello,雙擊Request。
    image
  5. 在彈出的界面中,將自己的參數輸入,然后點擊綠色三角形開始調用,因為我們這個方法沒有參數返回,所有調用后沒有什么信息會提示。
    image
  6. 打開我們的ide,此時就能看到下面打印了一行話,說明方法調用成功
    image

參考

https://zhuanlan.zhihu.com/p/37738632
https://blog.csdn.net/u011350541/article/details/71941536


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM