Problem description

If your client accesses the GameShield server over HTTP or HTTPS and the domain name is replaced with the IP address of the GameShield server in the host property of the URL, the request is sent by using the IP address instead of the domain name. In this case, the value of the host property that is obtained by the GameShield server is the IP address of the server. The GameShield server responds to the request in one of the following ways:
  • If the GameShield server is configured with only one domain name, it may ignore the value of the host property and return the correct page.
  • If the GameShield server is configured with multiple domain names, it returns 404 or 403 error code.

If your client accesses the GameShield server over HTTPS, the GameShield server may not be able to find a matching Secure Sockets Layer (SSL) certificate. As a result, the GameShield server returns only the default SSL certificate or does not return an SSL certificate. In this case, your client cannot pass the SSL certificate verification. This occurs because the SSL certificate contains the domain name of the GameShield server while the host property of the URL is set to the IP address of the Gameshield server.

Traditional solutions

Access the GameShield server over HTTP

The solution is simple if your client accesses the GameShield server over HTTP. In most cases, third-party libraries provide interfaces that allow developers to change the value of the host property in an HTTP request header to the required domain name.

Access the GameShield server over HTTPS

  • Troubleshooting in Android
    • Troubleshoot the failure of SSL certificate verification

      During an SSL handshake, your client checks whether the value of the host property in the requested URL is a domain name that is included in the SSL certificate provided by the GameShield server. For example, if the original requested URL is https://a.b.com, the URL that is obtained by the GameShield server becomes https://1.2.3.4.

      Because the host property of the URL is set to the IP address of the Gameshield server, your client cannot pass the SSL certificate verification, which results in a request failure.

      In most cases, an Android operating system provides an interface that allows you to verify whether the value of the host property in the URL matches that in an SSL certificate. You can use the interface to replace the IP address of the GameShield server in the host property of the URL with the domain name. Then, the issue can be resolved.

      Sample code in Java
      HostnameVerifier hnv = new HostnameVerifier() {
      @Override
      public boolean verify(String hostname, SSLSession session) {
      //Example
      if("yourhostname".equals(hostname)){ 
      return true; 
      } else { 
      HostnameVerifier hv =
      HttpsURLConnection.getDefaultHostnameVerifier();
      return hv.verify(hostname, session);
      }
      }
      };
      
      HttpsURLConnection.setDefaultHostnameVerifier(hnv);
    • Troubleshoot server name indication (SNI) issues

      Your client sends a request to the GameShield server by using the IP address. In this case, the value of the host property obtained by the GameShield server is the IP address of the server. However, the GameShield server is configured with multiple domain names. The obtained IP address of the GameShield server cannot match any of the domain names in the SSL certificate provided by the GameShield server.

      An Android operating system provides an interface that allows your client to pass in a custom SSLSocketFactory. The SSLSocketFactory is used to create SSLSocket objects. SSLSocket is an extension of the socket protocol and provides an SSL handshake function. An Android operating system provides the SSLCertificateSocketFactory implementation class to resolve issues caused by SNIs.

      Sample code in Java

      conn.setSSLSocketFactory(new SSLSocketFactory(){
      @Override
      public Socket createSocket(Socket s, String host, int port,boolean autoClose) throws IOException{
      SSLCertificateSocketFactory sslSocketFactory = (SSLCertificateSocketFactory)SSLCertificateSocketFactory.getDefault(0);
      SSLSocket sslSocket = (SSLSocket)sslSocketFactory.createSocket(s, realHost,port,autoClose);
      sslSocket.setEnableProtocols(sslSocket.getSupportedProtocols());
      sslSocketFactory.setHostname(sslSocket, realHost);
      return sslSocket;
      }
      });
  • Troubleshooting in iOS
    • Troubleshoot the failure of SSL certificate verification

      Add a pre-process to the URLSession:didReceiveChallenge:completionHandler method in NSURLSession to change the value of domain from the IP address in the requested URL to the required domain name.

      Sample code in Objective-C

      - (void)URLSession:(NSURLSession *)session
      didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
      completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
      {
      NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
      NSURLCredential *credential = nil;
      
      // Pre-processing before an SSL certificate verification.
      NSString *domain = challenge.protectionSpace.host; // Obtain the value of the host property (domain name or IP address) in the current request. For example, 1.2.3.4.
      NSString *testHostIP = self.tempDNS[self.testHost];
      // The value of the Common Name (CN) field (the domain name issued by the SSL certificate) in the SSL certificate returned by the GameShield server may be inconsistent with the value of the host property.
      // Because the value of the host property is replaced with the IP address of the GameShield server before the request is sent, the value cannot match the domain name returned by the GameShield server during SSL certificate verification. This prevents the request from being sent.
      // Replace the IP address of the GameShield server with the required domain name before SSL certificate verification.
      if ([domain isEqualToString:testHostIP]) {
      domain = self.testHost; // Replace the IP address of the GameShield server with the required domain name a.b.com.
      }
      
      // The following logic of the code is the same as that in the AFURLSessionManager.m file in AFNetworking.
      if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
      if ([self evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:domain]) {
      // The evaluateServerTrust:forDomain method is used to check whether the SSL certificate returned by the GameShield server can be trusted during an SSL handshake.
      // Check whether the domain name in the requested URL is consistent with the CN field declared in the SSL certificate.
      credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
      if (credential) {
      disposition = NSURLSessionAuthChallengeUseCredential;
      } else {
      disposition = NSURLSessionAuthChallengePerformDefaultHandling;
      }
      } else {
      disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
      }
      } else {
      disposition = NSURLSessionAuthChallengePerformDefaultHandling;
      }
      
      if (completionHandler) {
      completionHandler(disposition, credential);
      }
      }
      For more information about the definition of the evaluateServerTrust:forDomain method, see the code in the AFSecurityPolicy module in AFNetworking. The sample code is in Objective-C.
      - (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain {
      // Create an SSL certificate verification policy.
      NSMutableArray *policies = [NSMutableArray array];
      if (domain) {
      // Check whether the domain name in the request is consistent with the CN field declared in the SSL certificate.
      [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
      } else {
      [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
      }
      
      // Bind the SSL certificate verification policy to serverTrust. serverTrust is the SSL certificate returned by the GameShield server.
      SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
      
      // Evaluate whether serverTrust can be trusted.
      // The evaluation is performed base on the official documentation at https://developer.apple.com/library/ios/technotes/tn2232/_index.html.
      // If the result is kSecTrustResultUnspecified or kSecTrustResultProceed, serverTrust passes the SSL verification.
      SecTrustResultType result;
      SecTrustEvaluate(serverTrust, &result);
      return (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);
      }
      								
    • Troubleshoot SNI issues

      You can troubleshoot SNI issues by using the underlying library named libcurl. This library support SNI fields.

      Sample code in Objective-C

      //{HTTPS domain name}:443:{IP address}
      NSString *curlHost = ...;
      _hosts_list = curl_slist_append(_hosts_list, curlHost.UTF8String);
      curl_easy_setopt(_curl, CURLOPT_RESOLVE, _hosts_list);
      The value of the curlHost parameter is the hosts_list struct in C. For example, you can set the value to {HTTPS domain name}:443:{IP address} or _hosts_list. By passing in CURLOPT_RESOLVE to the curl_easy_setopt method, you can configure the mapping in the HTTPS request. This way, SNI is set.

GameShield solutions

Alibaba Cloud GameShield provides you with a better solution:
  1. Resolve the domain name of the website to 127.0.0.1.
    Note Before you change the DNS record, make sure that the domain name does not have online services.
  2. If your client sends a request over HTTP or HTTPS, change the access mode from the original 127.0.0.1:Proxy port to Domain name:Proxy port to access the web server. The proxy port is returned by the getProxyTcpByDomain interface.
The issues, such as SSL verification and using one IP address to provide HTTPS services for multiple domains can be resolved. This solution saves you the need to modify code and offers better protection for the origin server.

GameShield solutions are more secure than traditional solutions. Traditional solutions expose domain names in code, if the domain name is configured with the IP address of the origin server, attackers can easily find the origin server. With GameShield, attackers cannot obtain the IP address of the origin server even if they find the domain name of the origin server.

We recommend that you use GameShield to resolve host property mismatch from the perspective of compatibility, simplicity, and security.