[英]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.