[Java] Identiteit van aanroepende code controleren

Pagina: 1
Acties:

  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 13-02 20:06

Gerco

Professional Newbie

Topicstarter
Ik ben een Java (1.4!) programma aan het schrijven en dat bestaat uit verschillende jarfiles. Vanzelfsprekend implementeren die jarfiles allemaal een stukje functionaliteit en zit de code om die functionaliteit op een zinvolle manier aan elkaar te knopen in de 'hoofdapplicatie'.

Nu ben ik een tijd geleden in C# iets tegengekomen (StrongNameIdentityPermission) waardoor het mogelijk is om te vereisen dat de assembly die een andere assembly probeert aan te roepen getekend is door een bepaalde persoon (door de signature met de public key te controleren). Heel eenvoudig in te stellen door een class-level attribute. Nu vroeg ik me af of er voor Java ook zoiets bestaat...

Ik heb een aantal jarfiles, namelijk programma.jar, db.jar, network.jar, etc. Nu wil ik dat db.jar en network.jar gaan eisen dat programma.jar door mij gesigned is (en vice versa) zodat mijn libraries niet door anderen gebruikt worden op manieren waar ze niet voor bedoeld zijn.

Ik heb eens lopen zoeken en ben deze site tegengekomen: http://www.securingjava.com/ Hierop is heel veel informatie te vinden over het sandboxen van untrusted code, maar dat is dus niet wat ik wil doen. Ik wil zorgen dat mijn code alleen gebruikt kan worden door mijn andere code.

Weet iemand of dit mogelijk is in Java en op welke manier? Ik kan natuurlijk wel unlock() achtige methods gaan verzinnen op mijn interfaces, maar daar ben ik geen fan van, ik heb liever iets wat met PKI werkt. Voor zover ik weet kan ik de standaard Java security policies niet gebruiken, daarmee kan de gebruiker instellen dat hij code van mij wel of niet wil runnen. Wat ik wil is dat mijn code bepaalt door welke andere code hij gerund mag worden, buiten de gebruiker om.

[ Voor 13% gewijzigd door Gerco op 19-07-2006 11:54 ]

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Tsja Strong Names en Identities zijn diep verweven binnen de .Net CLR. Als je zoiets na wil bouwen (of iets vergelijkbaars) in eigen code is het IMHO veel te makkelijk aan te passen door in de byte-code te gaan zitten grutten.

Een idee heb ik wel maar erg useable is het denk ik niet:
- Bouw je deel-jar's en maak daar hashes van.
- Zet deze hashes in een collection/array/whatever in de code van je main applicatie
- Kijk at runtime of de hash van de sub-jar nog klopt met wat je in de array hebt opgeslagen

Eventueel kun je dit zelfs automatiseren dmv een Ant build-task waarbij je een tooltje die array in een aparte file laat genereren en die later bij het builden van je main applicatie laat meecompilen.

Ik hoop dat je er wat aan hebt. Succes iig

Nu met Land Rover Series 3 en Defender 90


  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 13-02 20:06

Gerco

Professional Newbie

Topicstarter
Bytecodegrutters houd ik hier even geen rekening mee, de doelgroep gaat dat echt niet zitten doen :) Waar het me om gaat is het volgende:

Bij een produkt worden een aantal drivers (jdbc drivers in dit geval) meegeleverd. Die mogen alleen binnen dat produkt gebruikt worden (licentiegeneuzel) en momenteel gebeurt dat door een unlock() method aan te roepen met een soort key.

Het is natuurlijk veel te simpel om dat te omzeilen, dat heb ik zelfs in 5 minuten gedaan, aangezien die key toch ergens in de code of als resource in de jars aanwezig moet zijn. Daarom wilde ik iets gaan doen zodat die jdbc drivers gaan controleren of de class die ze aanroept wel van ons is, daarbij schoot de StrongNameIdentityPermission me binnen. Dat zou natuurlijk ideaal zijn, helaas dus niet mogelijk in Java.

Het is dus de driver die de controle moet gaan uitvoeren, dat zou eventueel in de constructor kunnen, dat is weliswaar niet helemaal veilig, maar 'close enough'. De vraag is hoe kan ik nu controleren door welke class ik ben aangeroepen en kan ik zijn signature controleren?

[edit2]
Het is "gelukt". Ik heb nu de volgende classes en packages:

a/SignedClass - De beveiligde class
b/CallingClass - Een class die SignedClass gebruikt
c/UnsignedCaller - Een andere class die SignedClass gebruikt

SignedClass heeft nu de volgende (brakke) implementatie:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package a;

import java.security.*;
import java.security.cert.*;

public class SignedClass {

    private SignedClass() {
        System.out.println("Signed Class constructor");
    }

    private static boolean checkSignature(java.lang.Class callerClass) {
        try {
            PublicKey myKey =
                ((java.security.cert.Certificate)SignedClass.class.getSigners()[0]).getPublicKey();

            ((java.security.cert.Certificate)callerClass.getSigners()[0]).verify(myKey);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }

    public static SignedClass getInstance() {
        try {
            if(checkSignature(Class.forName(new Throwable().getStackTrace()[1].getClassName()))) {
                return new SignedClass();
            }
        } catch(java.lang.ClassNotFoundException e) {
            e.printStackTrace();
        }

        return null;
    }
}


Hier checkt SignedClass dus de classname van de calling method, creert daar een java.lang.Class object van en checkt de signature van die class om te zien of die gesigned is met dezelfde private key als SignedClass zelf.

De output:
code:
1
2
3
4
5
6
7
8
9
gerco@gentoo ~/tmp/SignatureTest/jar $ java -cp UnsignedCaller.jar:SignedClass.jar c.UnsignedCaller
Creating SignedClass instance from UnsignedCaller
java.security.SignatureException: Signature does not match.
        at sun.security.x509.X509CertImpl.verify(X509CertImpl.java:440)
        at sun.security.x509.X509CertImpl.verify(X509CertImpl.java:383)
        at a.SignedClass.checkSignature(SignedClass.java:17)
        at a.SignedClass.getInstance(SignedClass.java:28)
        at c.UnsignedCaller.<init>(UnsignedCaller.java:10)
        at c.UnsignedCaller.main(UnsignedCaller.java:14)


Het grote zwakke punt is natuurlijk het bepalen van de aanroepende class, hoeveel nivos moet je de stack aflopen? Is het Class object wat ik van Class.forName() krijg wel echt de aanroepende Class etc. Heeft iemand hier nog ideeën over?

[ Voor 94% gewijzigd door Gerco op 19-07-2006 14:52 ]

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Hm ziet er leuk uit, maar zoals je zelf al zegt hoever moet je de stack doorlopen?
Zoals het nu gaat ben je al genaaid als iemand er een simpele wrapper omheen zet met toevallig die classname (ok hier zal waarschijnlijk nogal wat bruteforce geweld aan te pas moeten komen om die classname te achterhalen)
Ik zou ook veel meer error-checking inbouwen om er voor te zorgen dat er uit je verificatie code geen exceptions komen (op die SignatureException na dan) om op die manier te voorkomen dat er extra informatie uitkomt.
Morgen maar eens even mee spelen want dit ziet er leuk uit.

Nu met Land Rover Series 3 en Defender 90


  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 13-02 20:06

Gerco

Professional Newbie

Topicstarter
MTWZZ schreef op donderdag 20 juli 2006 @ 10:43:
Hm ziet er leuk uit, maar zoals je zelf al zegt hoever moet je de stack doorlopen?
Zoals ik het nu gedaan heb, loop ik de stack af tot ik een class tegenkom die niet in dezelfde package zit als de beveiligde class. De JVM eist dat classes die claimen in dezelfde package te zitten ook gesigned zijn met dezelfde key, dat lijkt me redelijk veilig dus.
Zoals het nu gaat ben je al genaaid als iemand er een simpele wrapper omheen zet met toevallig die classname (ok hier zal waarschijnlijk nogal wat bruteforce geweld aan te pas moeten komen om die classname te achterhalen)
Vanwege bovenstaande eis van de JVM gaat dat niet op vziw.
Ik zou ook veel meer error-checking inbouwen om er voor te zorgen dat er uit je verificatie code geen exceptions komen (op die SignatureException na dan) om op die manier te voorkomen dat er extra informatie uitkomt.
Uiteraard is dit maar een simpele test om te zien of het überhaupt mogelijk is. Ik heb al iets mooiers gebouwd wat ook een groot zwak punt van bovenstaande code weghaalt (hier is het namelijk voldoende om de beveiligde class opnieuw te packagen in een nieuwe jar die je zelf signed), de hashcode van de signerkey staat daar namelijk in de code en wordt gechecked.

De nieuwe code kan ik even niet posten, want die staat thuis en daar staat mijn PC niet aan, maar ik zal hem online zetten zodra ik er weer bij kan. Echt nuttig is dit overigens niet, want met een decompiler lukt het zowiezo om de class te runnen. Dat gaat zonder JVM ondersteuning van deze feature ook niet beter worden.

[edit]
De code staat nu online op http://svn.gdries.com/public/SecureLibrary . Er is een build.xml meegeleverd en "ant dist" levert 4 jarfiles op in de 'lib' directory:
- secure.jar : De jar met de beveiligde classes
- testcode.jar: Unsigned versie van de testcode
- testcode.gdries.jar: Testcode gesigned met mijn key (zit in de meegeleverde keystore)
- testcode.eve.jar: Testcode gesigned met de key van Eve Attacker (zit ook in de keystore).

De uitdaging is nu om een versie van TestCode.jar te maken die classes in secure.jar kan aanroepen zonder IllegalAccessExceptions te krijgen. Iig moet het checken van de hashcode van de key nog vervangen worden door een controle van de echte public key. Ik moet alleen nog even een manier vinden om die public key mee te compileren in SecureClass.

[edit2]
Er zit nu een echte PublicKey check in SecureClass ipv een hashCode check. Er zijn nog wel een paar ClassCastExceptions en NullPointerExceptions af te vangen...

[ Voor 30% gewijzigd door Gerco op 20-07-2006 13:50 ]

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Ah mooi dat je de code online hebt. Ga er zeker mee spelen :)

Nu met Land Rover Series 3 en Defender 90

Pagina: 1