IURIDereferencer arabirimini uygulama

Adobe AIR 1.5 ve üstü

XML imzasını doğrulamak için, IURIDereferencer arabirimi uygulamasını sağlamalısınız. Uygulama, bir XML imza belgesinin Reference öğeleri içindeki URI'lerin çözülmesinden ve özetin hesaplanabilmesi için verilerin döndürülmesinden sorumludur. İmza oluşturulduktan sonra başvurulan verilerin değiştirilip değiştirilmediğinin belirlenmesi için, hesaplanan özet imzadaki özetle karşılaştırılır.

Not: HTML tabanlı AIR uygulamaları, XML imzalarını doğrulamak için ActionScript uygulaması içeren bir SWF kitaplığını içe aktarmalıdır. IURIDereferencer arabirimi, JavaScript'te uygulanamaz.

IURIDerefencer arabirimi, uygulanması gereken tek bir dereference(uri:String) yöntemine sahiptir. XMLSignatureValidator nesnesi, imzadaki her başvuru için bu yöntemi çağırır. Bu yöntem, verileri bir ByteArray nesnesinde döndürmelidir.

Çoğu durumda, başvuran nesnenin başvurulan verileri konumlandırmasına olanak vermeye yönelik özellikler veya yöntemleri de eklemeniz gerekecektir. Örneğin, imzalanan veriler imzayla aynı belge içinde konumlandırıldıysa, XML belgesine başvuru sağlayan bir üye değişkeni ekleyebilirsiniz. dereference() yöntemi bu değişkeni başvurulan verileri konumlandırmak için URI ile birlikte kullanabilir. Benzer şekilde, imzalanan veriler yerel dosya sisteminde yer alan bir dizinde konumlandırıldıysa, dereference() yöntemi başvurulan dosyaları çözmek için bu dizine giden yolu sağlayan bir özelliğe ihtiyaç duyabilir.

XMLSignatureValidator, URI dizelerinin yorumlanması için tamamen başvuran nesneyi temel alır. URI'lere başvurmaya ilişkin standart kurallar, XML İmza ve Sözdizimi İşleme için W3C Önerisi'nin 4.3.3 bölümünde belirtilmiştir.

Zarflı imzalarda URI'lere başvurma

Zarflı bir XML imzası oluşturulduğunda, imza öğeleri imzalanan verilere eklenir. Örneğin, aşağıdaki mesajı bir zarflı imza yapısı kullanarak imzaladıysanız:

<message> 
    <data>...</data> 
</message>

Elde edilen imzalı belge şöyle görünür:

<message> 
    <data>...</data> 
     <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> 
        <SignedInfo> 
            <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> 
            <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> 
            <Reference URI=""> 
                <Transforms> 
                    <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> 
                </Transforms> 
                <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> 
                <DigestValue>yv6...Z0Y=</DigestValue> 
            </Reference> 
        </SignedInfo> 
        <SignatureValue>cCY...LQ==</SignatureValue> 
        <KeyInfo> 
            <X509Data> 
                <X509Certificate>MII...4e</X509Certificate> 
            </X509Data> 
        </KeyInfo> 
    </Signature> 
</message>

İmzanın, URI olarak boş bir dizeye sahip tek bir Reference öğesi içerdiğine dikkat edin. Bu bağlamda boş bir dize, belgenin köküne başvurur.

Ayrıca, dönüştürme algoritmasının zarflı imza dönüştürmenin uygulandığını belirttiğine dikkat edin. Zarflı imza dönüştürme uygulandığında, XMLSignatureValidator özeti hesaplamadan önce imzayı otomatik olarak belgeden siler. Bu, başvuran nesnenin verileri döndürmesi sırasında Signature öğesini kaldırması gerekmediği anlamına gelir.

Aşağıdaki örnek, zarflı imzalar için bir başvuran nesneyi gösterir:

package 
{ 
    import flash.events.ErrorEvent; 
      import flash.events.EventDispatcher;  
    import flash.security.IURIDereferencer; 
    import flash.utils.ByteArray; 
    import flash.utils.IDataInput; 
 
    public class EnvelopedDereferencer 
        extends EventDispatcher implements IURIDereferencer 
    { 
        private var signedMessage:XML; 
         
        public function EnvelopedDereferencer( signedMessage:XML ) 
        { 
            this.signedMessage = signedMessage; 
        } 
 
        public function dereference( uri:String ):IDataInput 
        { 
            try 
            { 
                if( uri.length != 0 ) 
                { 
                    throw( new Error("Unsupported signature type.") ); 
                } 
                var data:ByteArray = new ByteArray(); 
                data.writeUTFBytes( signedMessage.toXMLString() ); 
                data.position = 0; 
            } 
            catch (e:Error) 
                { 
                var error:ErrorEvent = 
                    new ErrorEvent("Ref error " + uri + " ", false, false, e.message); 
                this.dispatchEvent(error); 
                data = null; 
                throw new Error("Reference not resolvable: " + uri + ", " + e.message); 
            } 
            finally 
            { 
                return data; 
            } 
        }         
    } 
}

Bu dereferencer sınıfı, zarflı imza belgesini dereference() yöntemi tarafından kullanılabilir duruma getirmek için signedMessage parametresini içeren yapıcı işlevini kullanır. Zarflı imzadaki başvuru her zaman imzalı verilerin köküne başvurduğundan, dereferencer() yöntemi belgeyi bir bayt dizisine yazar ve döndürür.

Zarflanan ve ayrılan imzalarda URI'lere başvurma

İmzalı veriler imzanın kendisiyle aynı belgede yer aldığında, başvurulardaki URI'ler imzalanan öğelere yönelmek için genellikle XPath veya XPointer sözdizimini kullanır. XML İmza Sözdizimi ve İşleme için W3C Önerisi, yalnızca bu sözdizimini önerir, yani uygulamanızı karşılaşmayı beklediğiniz imzalar üzerine kurmalısınız (ve desteklenmeyen sözdiziminin üstesinden başarıyla gelebilmek için uygulamaya yeterli hata denetimini eklemelisiniz).

AIR uygulamasının imzası, bir zarflanan imza örneğidir. Uygulamadaki dosyalar, Manifest öğesinde listelenmiştir. Manifest öğesi, Reference URI'sinde Manifest öğesinin kimliğine başvuran “#PackageContents” dizesi kullanılarak belirtilir.

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#" Id="PackageSignature"> 
    <SignedInfo> 
        <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> 
        <SignatureMethod Algorithm="http://www.w3.org/TR/xmldsig-core#rsa-sha1"/> 
        <Reference URI="#PackageContents"> 
            <Transforms> 
                <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> 
            </Transforms> 
            <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> 
            <DigestValue>ZMGqQdaRKQc1HirIRsDpeBDlaElS+pPotdziIAyAYDk=</DigestValue> 
        </Reference> 
    </SignedInfo> 
    <SignatureValue Id="PackageSignatureValue">cQK...7Zg==</SignatureValue> 
    <KeyInfo> 
        <X509Data> 
            <X509Certificate>MII...T4e</X509Certificate> 
        </X509Data> 
    </KeyInfo> 
    <Object> 
    <Manifest Id="PackageContents"> 
        <Reference URI="mimetype"> 
            <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"> 
            </DigestMethod> 
            <DigestValue>0/oCb84THKMagtI0Dy0KogEu92TegdesqRr/clXct1c=</DigestValue> 
        </Reference> 
        <Reference URI="META-INF/AIR/application.xml"> 
            <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"> 
            </DigestMethod> 
            <DigestValue>P9MqtqSdqcqnFgeoHCJysLQu4PmbUW2JdAnc1WLq8h4=</DigestValue> 
        </Reference> 
        <Reference URI="XMLSignatureValidation.swf"> 
            <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"> 
            </DigestMethod> 
            <DigestValue>OliRHRAgc9qt3Dk0m0Bi53Ur5ur3fAweIFwju74rFgE=</DigestValue> 
        </Reference> 
    </Manifest> 
</Object> 
</Signature>

Bu imzanın doğrulanması için başvuran nesne Reference öğesinden "#PackageContents" içeren URI dizesini almalı ve bir ByteArray nesnesinde Manifest öğesini döndürmelidir. “#” simgesi, öğe kimliği niteliğinin değerini belirtir.

Aşağıdaki örnek, AIR uygulama imzalarının doğrulanması için başvuran nesneyi uygular. Uygulama, bir AIR imzasının bilinen yapısı üzerine kurularak basit tutulmuştur. Genel amaçlı bir başvuran nesne, önemli ölçüde karmaşık olabilir.

package 
{ 
    import flash.events.ErrorEvent;    
    import flash.security.IURIDereferencer; 
    import flash.utils.ByteArray; 
    import flash.utils.IDataInput; 
     
    public class AIRSignatureDereferencer implements IURIDereferencer { 
        private const XML_SIG_NS:Namespace = 
            new Namespace( "http://www.w3.org/2000/09/xmldsig#" ); 
        private var airSignature:XML; 
     
        public function AIRSignatureDereferencer( airSignature:XML ) { 
            this.airSignature = airSignature; 
        } 
         
        public function dereference( uri:String ):IDataInput {     
            var data:ByteArray = null;     
            try 
            {     
                if( uri != "#PackageContents" ) 
                { 
                    throw( new Error("Unsupported signature type.") ); 
                } 
                var manifest:XMLList = 
                    airSignature.XML_SIG_NS::Object.XML_SIG_NS::Manifest; 
                data = new ByteArray(); 
                data.writeUTFBytes( manifest.toXMLString()); 
                data.position = 0; 
            } 
            catch (e:Error) 
            { 
                data = null; 
                throw new Error("Reference not resolvable: " + uri + ", " + e.message); 
            } 
            finally 
            { 
                return data; 
            } 
             
        } 
    } 
}

Bu türde bir imzayı doğruladığınızda, yalnızca Manifest öğesindeki veriler doğrulanır. Paketteki gerçek dosyalar hiç denetlenmez. Paket dosyalarıyla oynanıp oynanmadığını denetlemek için dosyaları okumalı, SHA256 özetini hesaplamalı ve sonucu bildirimde kayıtlı özetle harmanlamalısınız. XMLSignatureValidator, bunun gibi ikincil başvuruları otomatik olarak kontrol etmez.

Not: Bu örnek, imza doğrulama işlemini göstermek için sunulmuştur. AIR uygulamasında, kendi imzasını doğrulayan az sayıda kullanım bulunur. Uygulama değiştirildiyse, değişikliği yapan aracı doğrulama kontrolünü basit şekilde kaldırabilir.

Harici kaynaklar için özet değerlerini hesaplama

AIR, SHA256 özetlerinin hesaplanması için yerleşik işlevler içermez, ancak Flex SDK bir SHA256 yardımcı program sınıfı içerir. SDK ayrıca, hesaplanan özeti imzada saklanan özetle harmanlamak için kullanılabilen Base64 kodlayıcı yardımcı program sınıfını da içerir.

Aşağıdaki örnek işlev, bir AIR paket bildirimde yer alan dosyaları okur ve doğrular:

import mx.utils.Base64Encoder; 
import mx.utils.SHA256; 
 
private function verifyManifest( sigFile:File, manifest:XML ):Boolean 
{ 
    var result:Boolean = true; 
    var message:String = ''; 
    var nameSpace:Namespace = manifest.namespace(); 
     
    if( manifest.nameSpace::Reference.length() <= 0 ) 
    { 
        result = false; 
        message = "Nothing to validate."; 
    } 
    for each (var reference:XML in manifest.nameSpace::Reference) 
    { 
        var file:File = sigFile.parent.parent.resolvePath( reference.@URI ); 
        var stream:FileStream = new FileStream(); 
        stream.open(file, FileMode.READ); 
        var fileData:ByteArray = new ByteArray(); 
        stream.readBytes( fileData, 0, stream.bytesAvailable ); 
 
        var digestHex:String = SHA256.computeDigest( fileData ); 
        //Convert hexidecimal string to byte array 
        var digest:ByteArray = new ByteArray(); 
        for( var c:int = 0; c < digestHex.length; c += 2 ){ 
            var byteChar:String = digestHex.charAt(c) + digestHex.charAt(c+1); 
            digest.writeByte( parseInt( byteChar, 16 )); 
        } 
        digest.position = 0; 
         
        var base64Encoder:Base64Encoder = new Base64Encoder(); 
        base64Encoder.insertNewLines = false; 
        base64Encoder.encodeBytes( digest, 0, digest.bytesAvailable ); 
        var digestBase64:String = base64Encoder.toString(); 
        if( digestBase64 == reference.nameSpace::DigestValue ) 
        { 
            result = result && true; 
            message += "   " + reference.@URI + " verified.\n"; 
        } 
        else 
        { 
            result = false; 
            message += " ---- " + reference.@URI + " has been modified!\n"; 
        } 
        base64Encoder.reset(); 
    } 
    trace( message ); 
    return result; 
}

İşlev, Manifest öğesindeki tüm başvuruları dolaşır. Her başvuru için SHA256 özeti hesaplanır, base64 biçiminde kodlanır ve bildirimdeki özetle karşılaştırılır. AIR paketindeki URI'ler uygulama diziniyle ilişkili yollara başvurur. Yollar, her zaman uygulama dizini içindeki META-INF alt dizininde yer alan imza dosyasının konumu temel alınarak çözülür. Flex SHA256 sınıfının özeti bir onaltılı karakterler dizesi olarak döndürdüğüne dikkat edin. Bu dize, onaltılı dizeyle temsil edilen baytları içeren bir ByteArray nesnesine dönüştürülmelidir.

Flash CS4'te mx.utils.SHA256 ve Base64Encoder sınıflarını kullanmak için bu sınıfları konumlandırıp uygulama geliştirme dizininize kopyalayabilir veya Flex SDK kullanan sınıfları içeren bir SWF kitaplığı derleyebilirsiniz.

Harici verilere başvuran ayrılan imzalarda URI'lere başvurma

URI harici bir kaynağa başvurduğunda, verilere erişilmeli ve veriler bir ByteArray nesnesine yüklenmelidir. URI mutlak bir URL içeriyorsa, bu sadece dosyanın okunması veya URL'nin istenmesi anlamına gelir. En yaygın rastlanan durum olan URI'nin göreli bir yol içermesi durumunda, IURIDereferencer uygulamanız imzalanan dosyalara giden yolları çözmek için bir yol içermelidir.

Aşağıdaki örnek, başvuran birim imzalanan dosyaların çözülmesi için temel olarak oluşturulduğunda başlatılan bir File nesnesini kullanır.

package 
{ 
    import flash.events.ErrorEvent; 
    import flash.events.EventDispatcher; 
    import flash.filesystem.File; 
    import flash.filesystem.FileMode; 
    import flash.filesystem.FileStream; 
    import flash.security.IURIDereferencer; 
    import flash.utils.ByteArray; 
    import flash.utils.IDataInput; 
    public class RelativeFileDereferencer 
        extends EventDispatcher implements IURIDereferencer 
    { 
        private var base:File; 
         
        public function RelativeFileDereferencer( base:File ) 
        { 
            this.base = base; 
        } 
 
        public function dereference( uri:String ):IDataInput 
        { 
            var data:ByteArray = null; 
            try{ 
                var referent:File = this.base.resolvePath( uri ); 
                var refStream:FileStream = new FileStream();             
                data = new ByteArray(); 
                refStream.open( referent, FileMode.READ ); 
                 
                refStream.readBytes( data, 0, data.bytesAvailable ); 
                 
            } catch ( e:Error ) { 
                data = null; 
                throw new Error("Reference not resolvable: " + referent.nativePath + ", " + e.message ); 
            } finally { 
                return data; 
            } 
        }         
    } 
}

dereference() işlevi, başvuru URI'si tarafından yöneltilen dosyayı basit şekilde konumlandırır, dosya içeriğini bir bayt dizisine yükler ve ByteArray nesnesini döndürür.

Not: Uzak harici başvuruları doğrulamadan önce, uygulamanızın kötü amaçla yapılandırılmış bir imza belgesi tarafından gerçekleştirilen “eve telefon” veya benzer türde bir saldırıya karşı ne kadar hassas olabileceğini göz önünde bulundurun.