1

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
4

1 に答える 1

3

これは多くの理由から非常に悪い考えです。サーバーを修正するか (可能であれば)、それを実行している人々に修正するように勧める方がはるかに優れています。

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パッケージを使用できるようにする必要があるため、stackの引数を変更してこれを含める必要があります。

--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
  }
于 2016-05-20T05:06:53.277 に答える