簡體   English   中英

您如何獲得http-conduit接受自簽名證書?

[英]How do you get http-conduit to accept self-signed certificates?

我使用http-conduit創建了一個程序,它需要與沒有有效TLS證書的服務器通信。 在這種情況下,它是一個自簽名證書。

https-test.hs

#!/usr/bin/env stack
-- stack --install-ghc --resolver lts-5.13 runghc --package http-conduit
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.ByteString.Char8 as S8
import qualified Data.ByteString.Lazy.Char8 as L8
import           Network.HTTP.Client
import           Network.HTTP.Simple
import           Network.Connection
                 ( TLSSettings(..) )

main :: IO ()
main = do
  authenticate "self-signed.badssl.com" "" ""

authenticate :: S8.ByteString
             -> L8.ByteString
             -> L8.ByteString
             -> IO ()
authenticate hostname username password = do
  let request
        = setRequestMethod "GET"
        $ setRequestSecure True
        $ setRequestPort 443
        $ setRequestHost hostname
        $ setRequestPath "/"
        $ defaultRequest
  response <- httpLBS request
  putStrLn $ "The status code was: " ++
             show (getResponseStatusCode response)
  print $ getResponseHeader "Content-Type" response
  L8.putStrLn $ getResponseBody response

預期產量

The status code was: 200
["text/html"]
<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="shortcut icon" href="/icons/favicon-red.ico"/>
  <link rel="apple-touch-icon" href="/icons/icon-red.png"/>
  <title>self-signed.badssl.com</title>
  <link rel="stylesheet" href="/style.css">
  <style>body { background: red; }</style>
</head>
<body>
<div id="content">
  <h1 style="font-size: 12vw;">
    self-signed.<br>badssl.com
  </h1>
</div>

</body>
</html>

實際輸出:

https-test.hs: TlsExceptionHostPort (HandshakeFailed (Error_Protocol ("certificate rejected: [SelfSigned]",True,CertificateUnknown))) "self-signed.badssl.com" 443

由於許多原因,這是一個非常糟糕的主意 您最好修復服務器(如果可以的話),或者鼓勵運行它的人修復它。

繞過TLS證書驗證會刪除TLS的所有有用方面,因為它使處於中間人位置的攻擊者假裝成為服務器並操縱數據很容易。 攻擊者所要做的全部工作是使用另一個同樣糟糕的自簽名證書來重新加密其被攔截,操縱的內容。 您的客戶端軟件將是最明智的選擇。

http-conduit支持請求管理器的概念。 使用請求管理器,您可以提供替代方案。

首先,您可以構造一個TLSSettingsSimple來禁用服務器證書驗證( TLSSettingsSimple連接包的Network.Connection中定義 ):

noVerifyTlsSettings :: TLSSettings
noVerifyTlsSettings = TLSSettingsSimple
  { settingDisableCertificateValidation = True
  , settingDisableSession = True
  , settingUseServerName = False
  }

然后,您可以創建一個使用該請求管理器的請求管理器( mkManagerSettings來自http-client-tls包中的Network.HTTP.Client.TLS模塊 ):

noVerifyTlsManagerSettings :: ManagerSettings
noVerifyTlsManagerSettings = mkManagerSettings noVerifyTlsSettings Nothing

然后,您可以初始化此請求管理器並在請求上進行設置:

manager <- newManager noVerifyTlsManagerSettings
-- ...
$ setRequestManager manager
-- ...

您還需要為此提供http-client-tls包,因此您需要修改堆棧的參數以包括以下內容:

--package http-client-tls

這是完整的解決方案:

#!/usr/bin/env stack
-- stack --install-ghc --resolver lts-5.13 runghc --package http-client-tls
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.ByteString.Char8 as S8
import qualified Data.ByteString.Lazy.Char8 as L8
import           Network.HTTP.Client
import           Network.HTTP.Client.TLS (mkManagerSettings)
import           Network.HTTP.Simple
import           Network.Connection (TLSSettings(..))

main :: IO ()
main = do
  authenticate "self-signed.badssl.com" "" ""

authenticate :: S8.ByteString
             -> L8.ByteString
             -> L8.ByteString
             -> IO ()
authenticate hostname username password = do
  manager <- newManager noVerifyTlsManagerSettings
  let request
        = setRequestMethod "GET"
        $ setRequestSecure True
        $ setRequestPort 443
        $ setRequestHost hostname
        $ setRequestPath "/"
        $ setRequestManager manager
        $ defaultRequest
  response <- httpLBS request
  putStrLn $ "The status code was: " ++
             show (getResponseStatusCode response)
  print $ getResponseHeader "Content-Type" response
  L8.putStrLn $ getResponseBody response

noVerifyTlsManagerSettings :: ManagerSettings
noVerifyTlsManagerSettings = mkManagerSettings noVerifyTlsSettings Nothing

noVerifyTlsSettings :: TLSSettings
noVerifyTlsSettings = TLSSettingsSimple
  { settingDisableCertificateValidation = True
  , settingDisableSession = True
  , settingUseServerName = False
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM