简体   繁体   English

您如何获得http-conduit接受自签名证书?

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

I have created a program using http-conduit and it needs to talk to a server that doesn't have a valid TLS certificate. 我使用http-conduit创建了一个程序,它需要与没有有效TLS证书的服务器通信。 It's a self-signed certificate in this case. 在这种情况下,它是一个自签名证书。

https-test.hs : 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

Expected output 预期产量

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>

Actual output: 实际输出:

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

This is very bad idea for many reasons. 由于许多原因,这是一个非常糟糕的主意 You are much better off fixing the server (if you can) or encouraging the people who run it to fix it. 您最好修复服务器(如果可以的话),或者鼓励运行它的人修复它。

Bypassing TLS certificate validation removes all useful aspects of TLS, because it makes it trivial for an attacker in a man-in-the-middle position to pretend to be the server and manipulate data. 绕过TLS证书验证会删除TLS的所有有用方面,因为它使处于中间人位置的攻击者假装成为服务器并操纵数据很容易。 All the attacker needs to do it re-encrypt their intercepted, manipulated content with another equally bad self-signed cert. 攻击者所要做的全部工作是使用另一个同样糟糕的自签名证书来重新加密其被拦截,操纵的内容。 Your client software will be none the wiser. 您的客户端软件将是最明智的选择。

http-conduit supports the concept of a request manager. http-conduit支持请求管理器的概念。 Using a request manager you can supply an alternative. 使用请求管理器,您可以提供替代方案。

First you can construct a TLSSettingsSimple that disables server certificate validation ( TLSSettingsSimple is defined in Network.Connection in the connection package ): 首先,您可以构造一个TLSSettingsSimple来禁用服务器证书验证( TLSSettingsSimple连接包的Network.Connection中定义 ):

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

Then you can make a request manager that uses that ( mkManagerSettings comes from the Network.HTTP.Client.TLS module in the http-client-tls package ): 然后,您可以创建一个使用该请求管理器的请求管理器( mkManagerSettings来自http-client-tls包中的Network.HTTP.Client.TLS模块 ):

noVerifyTlsManagerSettings :: ManagerSettings
noVerifyTlsManagerSettings = mkManagerSettings noVerifyTlsSettings Nothing

Then you can initialize this request manager and set it on the request: 然后,您可以初始化此请求管理器并在请求上进行设置:

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

You'll also need to have the http-client-tls package available for this so you need to modify the arguments for stack to include this: 您还需要为此提供http-client-tls包,因此您需要修改堆栈的参数以包括以下内容:

--package http-client-tls

Here's the complete solution: 这是完整的解决方案:

#!/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