- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
gite: https://gitee.com/tickbh/wmproxy 。
github: https://github.com/tickbh/wmproxy 。
TLS双向认证是指 客户端和服务器端都需要验证对方的身份 ,也称 mTLS .
在建立Https连接的过程中,握手的流程比单向认证多了几步.
TLS是安全套接层(SSL)的继任者,叫传输层安全(transport layer security)。说直白点,就是在明文的上层和TCP层之间加上一层加密,这样就保证上层信息传输的安全,然后解密完后又以原样的数据回传给应用层,做到与应用层无关,所以http加个s就成了https,ws加个s就成了wss,ftp加个s就成了ftps,都是从普通tcp传输转换成tls传输实现安全加密,应用相当广泛.
单向通讯的示意图如下 。
双向通讯的示意图如下,差别 。
备注:客户端将之前所有收到的和发送的消息组合起来,并用hash算法得到一个hash值,然后用客户端密钥库的私钥对这个hash进行签名,这个签名就是CertificateVerify message; 。
将原来的 rustls 中的TlsAcceptor和TlsConnector进行相应的改造,变成可支持双向认证的加密结构.
获取TlsAcceptor的认证 。
/// 获取服务端https的证书信息
pub async fn get_tls_accept(&mut self) -> ProxyResult<TlsAcceptor> {
if !self.tc {
return Err(ProxyError::ProtNoSupport);
}
let certs = Self::load_certs(&self.cert)?;
let key = Self::load_keys(&self.key)?;
let config = rustls::ServerConfig::builder().with_safe_defaults();
// 开始双向认证,需要客户端提供证书信息
let config = if self.two_way_tls {
let mut client_auth_roots = rustls::RootCertStore::empty();
for root in &certs {
client_auth_roots.add(&root).unwrap();
}
let client_auth = rustls::server::AllowAnyAuthenticatedClient::new(client_auth_roots);
config
.with_client_cert_verifier(client_auth.boxed())
.with_single_cert(certs, key)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?
} else {
config
.with_no_client_auth()
.with_single_cert(certs, key)
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?
};
let acceptor = TlsAcceptor::from(Arc::new(config));
Ok(acceptor)
}
获取TlsAcceptor的认证 。
/// 获取客户端https的Config配置
pub async fn get_tls_request(&mut self) -> ProxyResult<Arc<rustls::ClientConfig>> {
if !self.ts {
return Err(ProxyError::ProtNoSupport);
}
let certs = Self::load_certs(&self.cert)?;
let mut root_cert_store = rustls::RootCertStore::empty();
// 信任通用的签名商
root_cert_store.add_trust_anchors(
webpki_roots::TLS_SERVER_ROOTS
.iter()
.map(|ta| {
rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
ta.subject,
ta.spki,
ta.name_constraints,
)
}),
);
for cert in &certs {
let _ = root_cert_store.add(cert);
}
let config = rustls::ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_cert_store);
if self.two_way_tls {
let key = Self::load_keys(&self.key)?;
Ok(Arc::new(config.with_client_auth_cert(certs, key).map_err(
|err| io::Error::new(io::ErrorKind::InvalidInput, err),
)?))
} else {
Ok(Arc::new(config.with_no_client_auth()))
}
}
这里默认信任的通用的CA签发证书平台,像系统证书,浏览器信任的证书,只有第一步把基础的被信任才有资格做签发证书平台.
至此双向TLS的能力已经达成,感谢前人的经典代码才能如此轻松.
首先先定义协议的Token结构,只有sock_map为0接收此消息 。
/// 进行身份的认证
#[derive(Debug)]
pub struct ProtToken {
username: String,
password: String,
}
下面是编码解码,密码要求不超过255个字符,即长度为1字节编码 。
pub fn parse<T: Buf>(_header: ProtFrameHeader, mut buf: T) -> ProxyResult<ProtToken> {
let username = read_short_string(&mut buf)?;
let password = read_short_string(&mut buf)?;
Ok(Self { username, password })
}
pub fn encode<B: Buf + BufMut>(self, buf: &mut B) -> ProxyResult<usize> {
let mut head = ProtFrameHeader::new(ProtKind::Token, ProtFlag::zero(), 0);
head.length = self.username.as_bytes().len() as u32 + 1 + self.password.as_bytes().len() as u32 + 1;
let mut size = 0;
size += head.encode(buf)?;
size += write_short_string(buf, &self.username)?;
size += write_short_string(buf, &self.password)?;
Ok(size)
}
如果服务端启动的时候配置了 username 及 password 则表示他需要密码验证, 。
let mut verify_succ = option.username.is_none() && option.password.is_none();
如果 verify_succ 不为true,那么我们接下来的第一条消息必须为 ProtToken ,否则客户端不合法,关闭 收到该消息则进行验证 。
match &p {
ProtFrame::Token(p) => {
if !verify_succ
&& p.is_check_succ(&option.username, &option.password)
{
verify_succ = true;
continue;
}
}
_ => {}
}
if !verify_succ {
ProtFrame::new_close_reason(0, "not verify so close".to_string())
.encode(&mut write_buf)?;
is_ready_shutdown = true;
break;
}
认证通过后消息处理和之前的一样,验证流程完成 。
最后此篇关于12.用Rust手把手编写一个wmproxy(代理,内网穿透等),TLS的双向认证信息及token验证的文章就讲到这里了,如果你想了解更多关于12.用Rust手把手编写一个wmproxy(代理,内网穿透等),TLS的双向认证信息及token验证的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在寻找的服务器是: 轻量级, 非 buggy , 支持.NET, 在客户端上运行以进行测试, 在Windows上运行 Cassinni太过马车,IIS太昂贵,Apache很难安装,XSP仅是lin
所以我有大约10个短的css文件,可以与mvc应用程序一起使用。 有像 error.css login.css 等等... 仅有一些非常短的CSS文件,这些文件使更新和编辑变得容易(至少对我而言)。我
我正在编写程序来自动化 win32 表单。我正在使用 Microsoft UI 自动化库。我不知道如何获取和调用该表单上的预定义快捷键。现在我只需获取 MenuItem 的 AutomationEle
我有一个在后台线程上运行的及时操作。运行时,我当前将光标置于等待状态: Mouse.OverrideCursor = Cursors.Wait 我刚刚实现了一项功能,允许用户在厌倦等待时单击“取消”按
如何找到所有可能直接或间接调用给定方法的单元测试?当我更改方法时,我希望知道要运行的最佳测试;必须有一个工具! 因为我们有很多接口(interface),所以我对所有调用接口(interface)方法
我想知道,一个类会被装箱吗?我一直假设每个类都有一个虚拟表,可以用来标识类,所以它需要装箱吗? 最佳答案 只有值类型(结构)被装箱。类实例不会被装箱。 关于.net - 类是盒装的吗? 。网,我们在S
所以接下来有一个按钮调用(页面)。它的 href 链接是 site/blah/#。所以我知道它真正运行的 javascript 代码。在我解析完第一页后,我想解析下一页。我如何模拟鼠标点击,以便我可以
我想知道是否有人对解决以下设计问题有好的建议/模式。我有一个命令类的层次结构。在最抽象的层面上,我有一个 ICommand 接口(interface)。执行 ICommand 的 RunCommand
我在资源(xsd 文件)中有几个文件可用于验证收到的 xml 消息。我使用的资源文件名为 AppResources.resx,它包含一个名为 clientModels.xsd 的文件。当我尝试使用这样
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求提供代码的问题必须表现出对所解决问题的最低限度理解。包括尝试过的解决方案、为什么它们不起作用,以及预
(最后的简短版本) 我目前正在开发的软件需要跟踪任意数量的 MS Office 文件,现在需要提供将所有这些文件一起打印的功能,以及一些应用程序数据(可能会发送到打印机作为 .xps、.html 或
我想在不指定命名空间或程序集的情况下按名称(字符串)实例化一个类。像这样(Unity 语法): var processor = container.Resolve("SpecialProcessor"
我有一些代码可以对 64 位整数进行大量比较,但是它必须考虑数字的长度,就好像它被格式化为字符串一样。我无法更改调用代码,只能更改函数。 最简单的方法(除了 .ToString().Length 之外
使用遗留代码,我发现我有很多这样的语句(超过 500 个) bool isAEqualsB = (a == b) ? true : false; 这样重写有意义吗? bool isAEqualsB =
我有这个: AudioPlayer player = new AudioPlayer(); player.Directory = vc.Directory; player.StartTime = vc
我已经阅读了很多关于双重检查锁定的危险的文章,我会努力远离它,但话虽如此,我认为他们的阅读非常有趣。 我正在阅读 Joe Duffy 的这篇关于使用双重检查锁定实现单例的文章: http://www.
对于可变类型,值类型和引用类型之间的行为差异很明显: // Mutable value type PointMutStruct pms1 = new PointMutStruct(1, 2); P
关闭。这个问题需要更多 focused .它目前不接受答案。 想要改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 6 年前。 Improve this q
我有一个 Cordova pp 我在 Controller 中调用post方法 它可以在浏览器中工作,但是在构建和调试apk时出现错误 ionic.bundle.js:23826 POST http:
我们正在尝试将时间戳附加到某些 URL 以让内容缓存但在它们发生更改时更新它们。我们有代码可以归结为: DateTime ts = File.GetLastWriteTime(absPath); 其中
我是一名优秀的程序员,十分优秀!