• 注册
  • SPTarkov 动态 SPTarkov 动态 关注:246 内容:59

    EFT internals research: Secured comminucation

  • 查看作者
  • 打赏作者
  • 当前位置: ODDBA社区 > SPTarkov 动态 > 正文
  • 6
  • SPTarkov 动态
  • SPT主创
    初窥堂奥
    VIP2
    SPTarkov项目组

    Hello everyone!

    It really has been a while!

    大家好!

    许久不见!


    While I sadly can't talk much about SPT-AKI's development since I'm out of the loop myself, I can talk a little about the research I've done so far on EFT and it's internal functionality. As such, this will be a technical article. I apologize to everyone for writing often on difficult topics, I'll try to simplify my explanations while still providing technical depth for those interested.

    虽说我不再能聊太多和SPT-AKI开发相关的事情(因为我本人已经不参与了),但是我能聊的是我当下对《逃离塔科夫》做的研究和其内部功能机理。因此这篇帖子将会是个技术帖。在此我为频繁发表晦涩难懂的技术帖道歉,我会尽量简化我的解释文字,但是依然为那些感兴趣的同好保留技术深度。

    Today, I would like to cover 4 aspects of EFT's internals in 4 different articles: secured comminucation, payload encryption, response caching and file integrity scanning. These articles are mostly aimed at SuperMod author and anyone else interested in making modding more secure.

    本次我会花4篇帖子涵盖《逃离塔科夫》的4个内部机制:加密通信、有效载荷加密、回复信息缓存和文件完整性扫描。这些帖子的主要受众是超级模块的作者,和其他想让模组制作更加坚固安全的同好。

    Secured comminucation

    加密通信

    Some might remember me talking about implementing a host of features in Haru (my EFT tech research server). While I'm still planning on doing this, it takes me a long time. This topic is one of the many reasons why.

    各位之中有些人可能还记得我想要在Haru,我的EFT技术研究服务器当中实装一系列功能的事情。这项计划不变,但是会花我很长的时间,这个话题是其中的一个原因。

    EFT's secure comminucation consists of two parts:

    《逃离塔科夫》的加密通信由两部分组成:

    – SSL encryption of traffic (HTTPS/WSS) 对流量进行SSL加密(HTTPS/WSS)
    – AES encryption of payload 对有效载荷进行AES加密

    The former was tried before in AKI 1.0.0-A1 up until AKI 2.2.1, then didged because NodeJS (the thing the server runs on) has poor support for generating the files (certificates, which authenticate if a client is genuine) required. Encrypted payloads (data send from the client to the server) was added in EFT 0.12.11, and was never explored by the AKI team. Instead, they opted for patches to disable it all.

    前者我们在AKI 1.0.0-A1一直到2.2.1版本都有做相关的尝试,然后因为NodeJS(服务器运行的基础框架)对生成文件(用来证明客户端真假的证书)支持很差就放弃了。

    经过加密的有效载荷(客户端向服务器发送的数据)是在0.12.11版本新增的,但是AKI团队从来没有研究过这个。他们选择用软件补丁直接把整个系统全部禁掉了

    Luckily enough for me, in C# (a programming language) it's much easier to get an SSL encrypted connection working and going. Yet, still complicated. How complicated? This complicated:

    对我来说幸运的是,在C#这个语言中创造运行一个SSL加密通信通道简单得多,但是还是很复杂。多复杂?这样复杂:

            // NET::ERR_CERT_AUTHORITY_INVALID
            private X509Certificate2 GenerateSelfSigned(string subject, DateTime start, DateTime end, string password)
            {
                using (var rsa = RSA.Create(2048))
                {
                    // allow multiple lookups
                    var builder = new SubjectAlternativeNameBuilder();
                    builder.AddIpAddress(IPAddress.Loopback);
                    builder.AddDnsName(“localhost”);

                    // create request for SSL server
                    var distinguishedName = new X500DistinguishedName($”CN={subject}”);
                    var req = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)
                    {
                        CertificateExtensions = {
                            new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false),
                            new X509EnhancedKeyUsageExtension(new OidCollection { new Oid(“1.3.6.1.5.5.7.3.1”) }, false),
                            builder.Build()
                        }
                    };
                    req.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(req.PublicKey, false));

                    // create certificate with both public and private key
                    var cert = req.CreateSelfSigned(start, end);

                    // export certificate
                    var bytes = cert.Export(X509ContentType.Pfx, password);
                    return new X509Certificate2(bytes, password, X509KeyStorageFlags.Exportable);
                }
            }
        }

    …and that's only the beginning! 而且这只是个开始!

    In EFT, X509 certificates are used for securing the comminucation. In the code above we generate a self-signed certificate that allows a server and client to connect over SSL. The connection must be TLS 1.2.

    在《逃离塔科夫》当中,X509证书是用来加密通信的。上面的代码会生成一个自签的证书,允许服务器和客户端通过SSL链接。整个连接必须使用TLS 1.2协议。

    Think of it as a passport: we validate the validity of the user at the border before they can enter the country. Normally passports are issued by the government (a Certificate Authority), but instead we forge our passport (self-signed). As such, both us and the country need to agree that our forged passport is valid in the country before we're allowed to enter. Not all passports are valid, with modern age our passports gain new protections to prevent counterfeits. TLS 1.2 is one of those methods for certificates.

    把这个证书想象成是个护照:我们必须要先在边检确认用户的身份才能允许ta入境。一般来说证书是由政府(证书颁发机构)发行,但是在这里我们伪造了这个“护照”(自签)。因此,我们和这个“国家”都需要认定这个假护照在这个国家境内合法有效,我们才能入境。不是所有的护照都是有效护照,随着时代进步我们的护照也有了新的防伪手段。TLS 1.2就是其中的一种。

    Using self-signed certificates is fine on a local network (see code above), but requires the server (HttpServer), requestor (HttpClient) and EFT to disable SSL cerificate validation. Ideally you get a proper certificate from LetsEncrypt! or another Certificate Authority organization. Usually you obtain one from buying a website domain.

    用自签的证书在本地局域网(参见上方代码)是没问题的,但是需要服务器(HttpServer)、请求方(HttpClient)和《逃离塔科夫》本身都禁用SSL证书验证。理想情况下你会从LetsEncrypt!或者其他证书颁发机构那里获得一个货真价实的证书。一般你会在买下一个网站域名的时候会拿到一个。

    Right now my research server doesn't have the capabilities yet to actually validate if the certificate is valid. As such, I disable it everywhere until I can get a reasonable implementation going. This might be the hardest part to implement.

    现在我的研究用服务器并没有验证证书是否有效的能力。因此我在所有相关的位置都禁用了验证证书的功能,直到我能实装一个合理的解决方案为止。这可能是最困难的一部分。

            private HttpServer CreateInstance(string address, string cert = null, string password = null)  
            {
                // …

                switch (protocol)
                {
                    case “https”:
                        server = new HttpServer(uri.Port, true);
                        server.SslConfiguration.ClientCertificateValidationCallback += IsCertificateValid;
                        server.SslConfiguration.EnabledSslProtocols = SslProtocols.Tls12;
                        server.SslConfiguration.ServerCertificate = new X509Certificate2(cert, password);

                        // todo: proper certificate validation
                        server.SslConfiguration.ClientCertificateRequired = false;
                }
           
                // …
            }

            private bool IsCertificateValid(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
            {
                // todo: proper certificate validation
                return true;
            }

    The code above shows how the research server set's up it's secure connection settings. It doesn't check the certificate validity yet, so IsCertificateValid always returns true (the certificate is always valid). server.SslConfiguration.ClientCertificateRequired is set to false so that the client doesn't need to provide a certificate.

    上面这段代码展示了研究用服务器配置加密连接设置的方式。它目前还不会验证证书有效性,所以IsCertificateValid永远返回true值(即证书永远有效)。server.SslConfiguration.ClientCertificateRequired设置为false,这样客户端就不需要提供证书了。

            public Client(string address, string accountId, string gameVersion)
            {
                // …

                // setup certificate handler
                var handler = new HttpClientHandler();
                handler.ServerCertificateCustomValidationCallback += IsCertificateValid;

                // setup http client
                _httpv = new HttpClient(handler)
                {
                    Timeout = TimeSpan.FromSeconds(5)
                };
            }

            private bool IsCertificateValid(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
            {
                // todo: proper certificate validation
                return true;
            }

    Above is the requestor code. It's very much the same as the server: set the certificate to always be valid.

    请求方代码如上。和服务器类似:把证书设置为永远有效。

    namespace Haru.Client.Patches
    {
        public class SslCertificatePatch : APatch
        {
            public SslCertificatePatch() : base()
            {
                Id = “com.Haru.Client.sslcertificate”;
                Type = EPatchType.Prefix;
            }

            protected override MethodBase GetOriginalMethod()
            {
                return PatchConsts.EftTypes.Single(x => x.BaseType == typeof(CertificateHandler))
                    .GetMethod(“ValidateCertificate”);
            }

            // todo: proper certificate validation
            protected static bool Patch(ref bool __result)
            {
                __result = true;
                return false;
            }
        }
    }

    At last for EFT, we're looking for the place inside EFT where they validate their own certificates, and replace that code with our own. Again, we're always set __result to true in order to always accept our certificate.

    最后对于《逃离塔科夫》的客户端来说,我们要找到他们验证自己的证书的代码位置,然后用我们自己的代码替换掉。同样地,我们会把__result永远设置为true以让它永远能接受我们的证书。

    After seeing how much code this takes and what kind of headaches this brings (and the heavy drinking that comes with that), one aught to wonder:

    看到这些代码和知道它们多让人头疼(和与之相关的大量饮酒行为)之后,你们可能会想:

    But, why?

    为什么研究这个?

    A very good question!

    For supermod author, a system like this is very beneficial: it allows supermod to talk to a server without the request being modified externally. This prevents man-in-the-middle attacks, or hackers on doing things on your behalf. This is not as important when you run everything locally on your machine, but as soon as you want other people to establish a connection and download / exchange things… security becomes a really big priority!

    好问题!

    对于超级模块的作者,类似这样的系统会有不少益处:它可以让超级模块在自己的请求不被篡改的情况下和服务器通信,防止中间人攻击,或者黑客以你的身份做一些事情的发生。你在自己的电脑上本地运行一切的时候问题不是太大,但是如果你想要别人连接到你,然后下载/交换文件的话…安全马上就会成一个大题!

    As always, security consists of layers. In the next article, I explain EFT's second layer of defense: payload encryption.

    当然了,安全是分很多层的。在下一个帖子中我将会解释《逃离塔科夫》的第二道防线:有效载荷加密。


    Future work

    后期工作

    Actually validating certificates! Man, that's gonna be a real pain… wish me luck!

    实装验证证书!这下真头疼了…祝我好运吧!

    渐入佳境
    2021

    前排!! 大大加油!


    回复
    渐入佳境
    VIP3
    赠送了礼物[肥仔快乐水]
    回复
    渐入佳境
    VIP3

    perhaps the best comparison(the passport one)

    回复
    已臻大成
    VIP5

    666

    回复
    略有小成
    2021
    赠送了礼物[666]
    回复
    略有小成
    2021
    打赏了1金币
    回复

    请登录之后再进行评论

    登录
  • 签到
  • 任务
  • 发布
  • 模式切换
  • 偏好设置
  • 帖子间隔 侧栏位置: