2015-08-03 38 views
6

Bir hizmetin farklı platformları ve uygulamaları arasında JSON nesneleri değiş tokuş etmek ve bütünlüğünü dijital imzalar aracılığıyla doğrulanabilir yapmak zorundayım. Böylece bir A platformu böyle bir nesne oluşturacak ve dijital bir imza yaratacaktır. Söz konusu imza daha sonra nesneye dahil edilir ve B platformuna gönderilir. JSON nesneleri, keyfi nitelikler ve veriler içerebilir.JSON nesnelerini imzalama

E.g. PHP'de: ör.,

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

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

    return $jsonObjectToSign; 
} 

Sorun şu ki, örn. Java'da, bir JSON nesnesinin özelliklerinin, onları eklediğiniz sırada (JSONObject.put() aracılığıyla) olup olmayacağını belirtmenin bir yolu yoktur. PHP bir

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

yaparsanız yani, ben muhtemelen farklı olacaktı, imzayı doğrulamak için deneyin, bir java tabanlı bir sunucuya aktarmak, yukarıda belirtildiği gibi bu nesneyi imzalamak json nesnesi deşifre ve nesnenin özniteliklerinin sırası.

İhtiyacım olan şey, kullanılan dil veya platformdan bağımsız olarak JSONObject öğesinden bir String oluşturmak için güvenilir bir yoldur.

Yukarıdaki örnek nesnenin her zaman {"a":1, "b":2} ve NEVER {"b":2, "a":1} çıkışına ihtiyacı vardır. Ne yazık ki, bu olağan durum örn. Java'da.

JSON Nesneleri güvenli bir şekilde imzalamak için herhangi bir "en iyi uygulama" var mı?

Ama beni başka bir şekilde sorunu tarif edelim:

ı Java bunu yapmak istiyor demek (veya başka bir dili) yapalım: Şimdi

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

, bir seri fonksiyonu gerekir ki Bu nesne için her zaman aynı dize temsili çıktıları, bu nesnenin nasıl ve hangi dilde oluşturulduğu önemli değildir.

+0

emin değil http://stackoverflow.com/questions/4670494/how-to-cryptographically-hash-a-json-object) bir kopyası, ama kesinlikle okumaya değer. JSON'un tekrarlanabilir bir karmayı garantilemek için kanonikleştirilmesi için birkaç fikir önerilmiştir. –

cevap

0

Şimdi bunu çözdüm. Başlık içindekiler hariç, JOSE'un yaptığı gibi. Ancak JOSE, ihtiyacım olmayan bir sürü havai (ve özellik) getiriyor gibi görünüyor. Bu yüzden aşağıdaki ile gitmeye karar verdi: eğer [bu] (

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

JSON öğelerinin sırasını diğer platform ve dillerden nasıl doğruladınız? –

+0

'jsonToSign' bir dize olarak serileştirildi ve sonra imzalandı. Bu, herhangi bir JSON uygulamasının imzayı doğrulamasına izin verir, ancak gerçek verilere ulaşmak için ekstra bir kodlama/kod çözme adımı gerektirir. –

2

JSFA'da henüz bir resmi (resmi olmayan) standardı olmayan bir AFAIK var olduğundan, muhtemelen özel bir uygulama yapabilirim. Yeni bir JSON nesnesini tanımlardım, ör. Sistemimin her iki tarafına da bir imzalama/imza doğrulama katmanı uygulayın ve uygulayın.

+0

Bu şu anda yaptığım şey.Her neyse, Nesneyi kullanırken ve ardından söz konusu base64 gösterimini oluştururken, muhtemelen farklı sistemlerde farklı bir base64 temsili alacağım. Bu nedenle, imzayı kontrol etmek muhtemelen başarısız olacaktır. – Xenonite

+1

Hayır, Base64 aynı olmalıdır (IMHO). Ya da demek istediniz ki, ör. Orijinal JSON dizesindeki alanların sırası farklılık gösterebilir ve bu nedenle Base64 dizesi farklı mıdır? Ama bu sorun olmamalı, orijinali değil Base64 dizesini imzalayacaksınız. Ayrıca, hedef sistemde olduğu gibi, hedef sisteme de bakmak zorunda değilsiniz, çünkü Base64 dizesinin ** imzasını ** doğrular, sonra orijinali almak için şifresini çözüp nihayet yüklersiniz. Ancak kod çözme ve yükleme ile artık imzayı önemsemiyorsunuz. –

+0

Evet, bahsettiğim sorun bu. Maalesef, bu String temsilini Framework'ümde "alamıyorum", sadece JSON Nesnesini aldım. Bu yüzden her zaman aynı base64 temsilini oluşturmanın bir yoluna ihtiyacım var. – Xenonite

3

JSON nesnelerinin imzalanması ve şifrelenmesi, JOSE'un Javascript Nesnesi İmzalama ve Şifreleme anlamına geldiği belirtimlerin JOSE paketinde belirtilmiştir, bkz. http://jose.readthedocs.org/en/latest/ JOSE, JSON nesnesinin bir base64url kodlama gösterimi üzerinden hesaplanan ayrılmış bir imza kullanır. İmza, JSON nesnesinin bir parçası değildir, dolayısıyla doğrulamak için yeniden sıralama gerekmez.

+0

JOSE henüz son değil, değil mi? –

+0

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

+0

Teşekkürler, bunu farketmediniz. –

-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

Yığın taşmasına hoş geldiniz :-) Lütfen [cevap] 'a bakın. Kodunuzun sorunu nasıl çözdüğü hakkında biraz bilgi vermelisiniz. Yalnızca kod yanıtları topluluk için yararlı değildir. – JimHawkins