2015-08-03 40 views
6

Tôi phải trao đổi các đối tượng JSON giữa các nền tảng khác nhau và việc triển khai dịch vụ và làm cho tính toàn vẹn của nó có thể xác minh được thông qua chữ ký số. Vì vậy, một nền tảng A sẽ tạo ra một đối tượng như vậy và tạo ra một chữ ký số. Chữ ký được cho sau đó được đưa vào đối tượng và được gửi đến nền tảng B. Các đối tượng JSON có thể chứa các thuộc tính và dữ liệu tùy ý.Ký các đối tượng JSON

Ví dụ: bằng PHP:

function signObject($jsonObjectToSign, $privateKey) { 
    $jsonObjectToSign->signature = ""; 
    $msgToSign = json_encode($jsonObjectToSign); 

    openssl_sign($msgToSign, $jsonObjectToSign->signature, $privateKey, OPENSSL_SLGO_SHA1); 

    return $jsonObjectToSign; 
} 

Vấn đề là, ví dụ: trong Java, không có cách nào để biết liệu các thuộc tính của một đối tượng JSON sẽ theo cùng một thứ tự mà bạn đã thêm chúng hay không (thông qua JSONObject.put()). Vì vậy, nếu tôi làm một

$json = json_encode('{"a":1, "b":2}'); 

trong PHP, đăng ký đối tượng này như đã nêu ở trên, chuyển nó đến một máy chủ java dựa, giải mã các đối tượng json và sau đó cố gắng xác minh chữ ký, tôi có lẽ sẽ nhận được một khác nhau thứ tự của các thuộc tính của đối tượng.

Vì vậy, những gì tôi cần, là một cách đáng tin cậy để tạo Chuỗi từ JSONObject, độc lập với ngôn ngữ hoặc nền tảng được sử dụng.

Đối tượng ví dụ ở trên cần luôn xuất ra {"a":1, "b":2} và KHÔNG BAO GIỜ {"b":2, "a":1}. Rất tiếc, đây là trường hợp thông thường, ví dụ: trong Java.

Có cách nào "thực hành tốt nhất" để ký đối tượng JSON một cách an toàn không?

Nhưng hãy để tôi mô tả các vấn đề theo một cách khác:

Hãy nói rằng tôi muốn làm điều này trong Java (hoặc bất kỳ ngôn ngữ khác):

JSONObject j = new JSONObject(); 
j.put("a", 1); 
j.put("b", 2); 

Bây giờ, tôi cần một chức năng serialization, mà kết quả đầu ra luôn là biểu diễn chuỗi giống nhau cho đối tượng này, cho dù đối tượng này được tạo ra bằng ngôn ngữ nào.

+0

Không chắc chắn nếu [này] (http://stackoverflow.com/questions/4670494/how-to-cryptographically-hash-a-json-object) là một bản sao, nhưng nó chắc chắn đáng đọc. Một vài ý tưởng được đề xuất để chuẩn hóa JSON để đảm bảo băm tái sản xuất. –

Trả lời

0

Đây là cách tôi đã giải quyết ngay bây giờ. Nó bằng cách nào đó tương tự như những gì JOSE làm, ngoại trừ tiêu đề. Nhưng JOSE dường như mang lại rất nhiều chi phí (và tính năng) mà tôi không cần. Vì vậy, tôi quyết định đi với những điều sau đây:

class Signature 
{ 
    private static $algorithm = OPENSSL_ALGO_SHA512; 
    private static $signaturePrefix = '-----BEGIN SIGNATURE-----'; 
    private static $signaturePostfix = '-----END SIGNATURE-----'; 

    public static function createSignature($message, $privateKey) 
    { 
     $signature = null; 

     openssl_sign($message, $signature, $privateKey, self::$algorithm); 

     return self::$signaturePrefix . base64_encode($signature) . self::$signaturePostfix; 
    } 

    public static function verifySignature($message, $publicKey, $signature) 
    { 
     $signature = str_replace(self::$signaturePrefix, '', $signature); 
     $signature = str_replace(self::$signaturePostfix, '', $signature); 

     return openssl_verify($message, base64_decode($signature), $publicKey, self::$algorithm); 
    } 

    public static function signJSON($jsonToSign, $privateKey) 
    { 
     if(gettype($jsonToSign) != 'string') 
      $jsonToSign = json_encode($jsonToSign); 

     $signedJSON = json_decode('{}'); 
     $sigedJSON->signature = self::createSignature($message, $privateKey); 
     $signedJSON->object = $jsonToSign; 

     return $signedJSON; 
    } 

    public static function verifyJSONSignature($jsonObject, $publicKey) 
    { 
     if(gettype($jsonObject->object) == 'string') 
      throw new Exception('Value $jsonObject->object must be a String, is a ' . gettype($jsonObject->object)); 

     return self::verifySignature($jsonObject->object, $publicKey, $jsonObject->signature); 
    } 
} 
+0

làm cách nào bạn xác minh thứ tự các phần tử của JSON trong nền tảng và ngôn ngữ khác? –

+0

'jsonToSign' được tuần tự hóa thành chuỗi và sau đó được ký. Điều này cho phép bất kỳ việc triển khai JSON nào để xác minh chữ ký, nhưng yêu cầu một bước mã hóa/giải mã bổ sung để nhận được dữ liệu thực tế. –

2

Vì có AFAIK không có tiêu chuẩn chính thức (không chính thức) trên JSON Signing, tôi có thể thực hiện tùy chỉnh. Tôi muốn xác định một đối tượng JSON mới, ví dụ:

{ 
    "original": "..." // original JSON as a Base64 encoded string 
    "signature": "..." // the signature 
} 

và triển khai lớp xác minh chữ ký/chữ ký trên cả hai mặt của hệ thống của tôi.

+0

Đây là điều tôi đang làm ngay bây giờ.Nhưng dù sao, khi sử dụng Object và sau đó tạo ra biểu diễn base64 cho biết, tôi có thể sẽ có một biểu diễn base64 khác nhau trên các hệ thống khác nhau. Do đó, việc kiểm tra chữ ký có thể sẽ thất bại. – Xenonite

+1

Không, Base64 phải giống nhau (IMHO). Hoặc bạn có nghĩa là, ví dụ: thứ tự của các trường trong chuỗi JSON gốc có thể khác nhau, và do đó chuỗi Base64 sẽ khác nhau? Nhưng điều này không có vấn đề gì, bạn sẽ ký chuỗi Base64, không phải chuỗi gốc. Và bạn không cần phải quan tâm đến thứ tự trường, như trên hệ thống đích, trước tiên bạn xác thực chữ ký ** của chuỗi Base64 **, sau đó giải mã nó để lấy bản gốc và cuối cùng tải nó. Nhưng bằng cách giải mã và tải bạn không quan tâm đến chữ ký nữa. –

+0

Vâng, đó là vấn đề tôi đang nói đến. Thật không may, tôi không "có được" đại diện String này trong khung của tôi, tôi chỉ nhận được đối tượng JSON. Vì vậy, tôi cần một cách để tạo ra cùng một đại diện base64 giống nhau. – Xenonite

3

Ký và mã hóa các đối tượng JSON được chỉ định trong bộ JOSE của các đặc tả trong đó JOSE là viết tắt của Javascript Object Signing and Encryption, xem http://jose.readthedocs.org/en/latest/ JOSE sử dụng chữ ký tách rời được tính toán trên biểu diễn mã hóa base64url của đối tượng JSON. Chữ ký không phải là một phần của đối tượng JSON do đó không yêu cầu đặt lại để xác thực nó.

+0

JOSE vẫn chưa kết thúc, phải không? –

+0

, xem: http://self-issued.info/?p=1387 –

+0

Cảm ơn, chưa nhận thấy điều đó. –

-1
JsonObject js = new JsonObject(); 
js.addProperty("c", "123"); 
js.addProperty("t", "yyyy-MM-dd'T'HH:mm:ss.SSSZ"); 
System.out.println("Json object == " + js); 
GenerateSignature util = new GenerateSignature(); 
String ecodedToken = util.signJSONObject(js); 
+0

Chào mừng bạn đến ngăn xếp tràn :-) Vui lòng xem [answer]. Bạn nên cung cấp một số thông tin tại sao mã của bạn giải quyết được vấn đề. Câu trả lời chỉ dành cho mã không hữu ích cho cộng đồng. – JimHawkins

Các vấn đề liên quan