2016-07-08 4 views
4

결국 IoT 용으로 예정된 UWP 앱을 C#으로 작성하고 있지만 지금은 로컬에서만 디버깅했습니다. Windows.Web.Http.HttpClient을 사용하여 작성한 자체 호스팅 WCF REST 웹 서비스에 연결하고 테스트를 위해 같은 시스템에서 콘솔 앱으로 실행하고 있습니다. 서비스에는 인증서와의 상호 인증이 필요하므로 CA 인증서, 서비스 인증서 및 클라이언트 인증서가 있습니다.UWP 앱 HttpClient HTTPS 클라이언트 인증서 문제

내 UWP 코드는 다음과 같이 작동합니다 : 클라이언트 인증서 및 CA 인증서에 대한

  1. 확인 응용 프로그램 인증서 저장소가 설치되어 있어야합니다.
  2. 그렇지 않은 경우 PFX 파일과 CER 파일에서 각각 설치하십시오.
  3. HttpBaseProtocolFilterCertificate를 부착하고 나는 다음과 같은 오류가 PostAsync 전화 후 HttpClient
  4. 를 호출 HttpClient.PostAsync

에 필터를 추가 An Error Occurred in the Secure Channel Support합니다. 온라인 검색을 많이하고 상식에 따라 상호 인증 된 SSL 연결을 설정하는 데 문제가있어서 HttpClient이 barfing이라고 확신합니다. 하지만 내 문제 해결을 기반으로 나는 이유를 알 수 없습니다.

더 이상, 나는 클라이언트 인증서가 요청에 첨부 된 평범한 이전 콘솔 응용 프로그램을 작성했습니다. 모든 것이 잘 작동합니다. 안타깝게도 System.Net은 UWP에서 완전히 지원되지 않습니다. 또한 UWP HttpClient에 인증서를 첨부하지 않으려 고 시도했으며 설치 된 인증서를 선택하는 UI가있는 앱이 나에게 메시지를 표시합니다. 올바른 인증서를 선택하고 여전히 동일한 예외가 발생합니다 (이 경우 최소한 인증서가 올바르게 설치되어 있고 앱의 관점에서 CA와 올바르게 인증됨을 알 수 있습니다). 추가로 브라우저에서 웹 서비스를 GET하고 메시지가 나타나면 클라이언트 인증서를 선택하고 파일을 다운로드 할 수 있습니다.

나는 Fiddler를 사용해 보았는데, 트래픽을 프록시하는 방식 때문에 내 웹 서비스가 금지 된 요청을 거부하는 것을 제외하고는 조금 더 효과가있는 것으로 여긴다. 아마도 Fiddler가 올바른 클라이언트를 포함하고 있지 않기 때문일 것이다. 인증서에있는 인증서). Windows에서 localhost를 사용하여 Wireshark를 작동 시키면 고통 스럽기 때문에 아직 Wireshark를 사용하지 않았습니다.

내 다음 단계는 클라이언트 인증을 요구하지 않도록 웹 서비스를 변경하고 이것이 문제인지 확인하는 것입니다.

두 가지 질문 :이 경우에는 Windows.Web.Http.HttClient이 작동하지 않는 이유는 무엇입니까? 덜 중요한, 좋은 HTTP 모니터링 도구에 대한 권장 사항을 통해이 문제를 더욱 자세히 디버깅 할 수 있습니까?

+0

이 자체 서명 인증서 표시입니다 시도? –

+0

나는'makecert'를 사용하여 CA 인증서를 만들고 그 인증서로부터'makecert'를 사용하여 클라이언트와 서비스 인증서를 발급했습니다. – koopaking3

+0

아마도 관련이 있습니다 : https://code.msdn.microsoft.com/windowsapps/How-to-ignore-Self-Signed-e50b89b6 –

답변

3

이 MSDN 게시물에 대한 답변이있는 것으로 나타났습니다. 미리 API에 별도의 의미없는 호출이 필요한 MS 부분에 대한 감독처럼 보입니다. 오 잘. 기사에서

http://blogs.msdn.com/b/wsdevsol/archive/2015/03/26/how-to-use-a-shared-user-certificate-for-https-authentication-in-an-enterprise-application.aspx

발췌 :

그러나 보안 서브 시스템은 공유 사용자 인증서 저장소에 저장된 인증서의 인증서 개인 키에 대한 액세스를 허용하기 전에 사용자의 확인이 필요합니다. 문제를 복잡하게하기 위해 클라이언트 인증서가 코드에 지정된 경우 하위 수준 네트워크 함수는 응용 프로그램이 이미이 문제를 처리 한 것으로 간주하고 사용자에게 확인을 요청하지 않습니다.

인증서와 관련된 Windows 런타임 클래스를 보면 인증서 개인 키에 대한 액세스를 명시 적으로 요청할 수있는 방법을 찾을 수 없으므로 앱 개발자는 무엇을해야합니까?

해결책은 선택된 인증서를 사용하여 작은 데이터 비트에 '서명'하는 것입니다. 응용 프로그램이 CryptographicEngine.SignAsync를 호출하면 기본 코드는 서명을 수행하기 위해 개인 키에 대한 액세스를 요청하고 응용 프로그램이 인증서 개인 키에 액세스 할 수 있도록 허용할지 묻습니다. 함수의 동기 버전 인 : Sign은 확인 대화 상자의 표시를 차단하는 옵션을 사용하므로이 함수의 'Async'버전을 호출해야합니다. 예를 들어

:

public static async Task<bool> VerifyCertificateKeyAccess(Certificate selectedCertificate) 
{ 
    bool VerifyResult = false; // default to access failure 
    CryptographicKey keyPair = await PersistedKeyProvider.OpenKeyPairFromCertificateAsync(
             selectedCertificate, HashAlgorithmNames.Sha1, 
             CryptographicPadding.RsaPkcs1V15); 
    String buffer = "Data to sign"; 
    IBuffer Data = CryptographicBuffer.ConvertStringToBinary(buffer, BinaryStringEncoding.Utf16BE); 

    try 
    { 
     //sign the data by using the key 
     IBuffer Signed = await CryptographicEngine.SignAsync(keyPair, Data); 
     VerifyResult = CryptographicEngine.VerifySignature(keyPair, Data, Signed); 
    } 
    catch (Exception exp) 
    { 
     System.Diagnostics.Debug.WriteLine("Verification Failed. Exception Occurred : {0}", exp.Message); 
     // default result is false so drop through to exit. 
    } 

    return VerifyResult; 
} 

당신은 다음 전에 응용 프로그램 인증서 개인 키에 액세스 할 수 있도록하기 위해 클라이언트 인증서를 사용하여이 함수를 호출하기 이전 코드 예제를 수정할 수 있습니다.

0
  1. 인증서 프로젝트
  2. (첨부 파일 경로를 제공)
  3. 우르 프로젝트 사용의 프리스트 서비스 요청은 다음 코드가 대부분이다 인증서 확인을 무시하는 발현 된 파일에 인증서를 추가 파일 추가 로그인 기능에 적합합니다.

는 {

  var filter = new HttpBaseProtocolFilter(); 
      filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired); 
      filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted); 
      filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName); 
      filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.RevocationFailure); 
      filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.RevocationInformationMissing); 
      filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.WrongUsage); 
      filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.IncompleteChain); 

      Windows.Web.Http.HttpClient client = new Windows.Web.Http.HttpClient(filter); 
      TimeSpan span = new TimeSpan(0, 0, 60); 
      var cts = new CancellationTokenSource(); 
      cts.CancelAfter(span); 
      var request = new Windows.Web.Http.HttpRequestMessage() 
      { 
       RequestUri = new Uri(App.URL + "/oauth/token"), 
       Method = Windows.Web.Http.HttpMethod.Post, 
      }; 
      //request.Properties. = span; 
      string encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(Server_Username + ":" + Server_Password)); 
      var values = new Dictionary<string, string> 
       { { "grant_type", "password" },{ "username", Uname}, { "password", Pwd }}; 
      var content = new HttpFormUrlEncodedContent(values); 
      request.Headers.Add("Authorization", "Basic " + encoded); 
      request.Content = content; 
      User root = new User(); 
      using (Windows.Web.Http.HttpResponseMessage response = await client.SendRequestAsync(request).AsTask(cts.Token)) 
      { 
       HttpStatusCode = (int)response.StatusCode; 
       if (HttpStatusCode == (int)HttpCode.OK) 
       { 
        using (IHttpContent content1 = response.Content) 
        { 
         var jsonString = await content1.ReadAsStringAsync(); 
         root = JsonConvert.DeserializeObject<User>(jsonString); 
         App.localSettings.Values["access_token"] = root.Access_token; 
         App.localSettings.Values["refresh_token"] = root.Refresh_token; 
         App.localSettings.Values["expires_in"] = root.Expires_in; 
         var json = JsonConvert.SerializeObject(root.Locations); 
         App.localSettings.Values["LocationList"] = json; 
         App.localSettings.Values["LoginUser"] = Uname; 
        } 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      ex.ToString(); 
     }