Úvod do problematiky ochrany software
Ochrana duševního vlastnictví u software byla vždy problémem číslo jedna. Obzvlášť v dnešní době, kdy komerční software vyvíjí desítky až stovky lidí řádově roky je v zájmu firem ho co nejlépe zabezpečit před potenciální nelegální distribucí a zpětným získáním zdrojového kódu. Jako první je třeba poznamenat, že stoprocentně spolehlivá ochrana software neexistuje, dá se pouze více či méně znesnadnit prolomení ochrany. Před implementací ochrany je třeba zvážit mnoho faktorů, například složitost implementace vs. účinnost, nebo dopad na uživatele softwaru. Online ověřování, hardwarový klíč, nebo nutnost přítomnosti DVD v mechanice patří mezi ty typy ochran, které mají nejvíce negativní působení na uživatele. Naopak prosté sériové číslo má prakticky nulovou účinnost.
Problematika ochrany ještě narůstá s příchodem a rozšířením platformy Microsoft .NET, kde je zpětné získání zdrojového kódu nebo vložení vlastních instrukcí do existující aplikace skutečně hračka ve srovnání s nativními Win32 aplikacemi, kde je obvykle nutná velmi dobrá znalost assembleru a jazyků C/C++.
Zabránění zpětného získání zdrojového kódu
Nástroje jako .NET Reflector dokážou ze zkompilované .NET assembly získat téměř identický původní zdrojový kód a zobrazit ho v jazyce vlastního výběru (IL, Visual Basic, C#, F#…). Tento proces je znám jako tzv. Reverse engineering a díky němu lze vytvářet např. ilegální generátory licencí známé jako keygeny. Jako první krok v ochraně aplikace je tedy potřeba co nejvíce znesnadnit tento proces. To se provádí pomocí různých nástrojů k tomu určených, příkladem může být Dotfuscator Community Edition, který je dodáván s Visual Studiem Standard nebo lepším. Tento nástroj ale dokáže pouze přejmenovávat a to ještě tak hloupě, že jsou názvy čitelné. Ideální obfuskátor (nástroj pro “zmatení” kódu) by měl kromě přejmenování tříd a jejich členů (tzv. Unicode normalizace) nějakým způsobem zabránit zobrazení původního zdrojového kódu při zachování plné funkčnosti aplikace a žádném nebo minimálním negativním dopadu na výkon. Následující příklad ukazuje původní kód, kód dekompilovaný před obfuskací a po obfuskaci.
Private Function GetQueryValue(ByVal url As String, ByVal parameter As String) As String
Dim firstOccurence = url.IndexOf(parameter, StringComparison.OrdinalIgnoreCase)
If firstOccurence > -1 Then
Dim builder As New StringBuilder(url.Length - firstOccurence - parameter.Length)
Dim a = firstOccurence + parameter.Length
Dim z = url.Length - 1
For index = a To z
If url(index) <> "&" Then
builder.Append(url(index))
Else
Exit For
End If
Next
Return builder.ToString()
Else
Return Nothing
End If
End Function
Nástrojů pro obfuskaci kódu existuje velké množství (bezplatné i komerční), ale pouze malá část z nich je skutečně účinná a stojí za to (např. ten, který používám já a jehož výsledek můžete vidět na obrázku je jeden z těch nejlepších). I když to ve většině případů není potřeba, umí některé obfuskátory i šifrovat textové řetězce v kódu a v resources. To se vám bude hodit, pokud máte hesla a jiné citlivé informace prasácky uložené přímo v kódu. Obfuskátory jsou buď plnohodnotné aplikace s uživatelským rozhraním, nebo konzolové aplikace ovládané parametry z příkazové řádky což je lepší, protože je lze integrovat do build procesu (pomocí Post-build události).
Zabránění nežádoucí modifikace nebo podvržení assembly
Nejdůležitější část ochrany aplikace je zabránění možnosti nežádoucí změny assembly nebo jejímu podvržení falešnou knihovnou. Realizace takové ochrany je velmi jednoduchá a vystačíte si s prostředky Visual Studia. Klíčem k realizaci je podepsání assembly silným názvem (Strong Name). Silný název zajišťuje unikátnost assembly v rámci systému, integritu assembly a autora assembly. Assembly můžete podepsat buď párem klíčů vytvořeným ve Visual Studiu (nebo nástroji z .NET Framework SDK) nebo komerčním certifikátem Authenticode vydaným některou z důvěryhodných certifikačních autorit. Druhá možnost má tu nevýhodu, že se kontroluje platnost certifikátu a po jejím ukončení vám systém nedovolí takto podepsanou aplikaci spustit (kromě toho obnovení platnosti certifikátu stojí nemalou částku a je ho třeba obnovovat pravidelně). Může se vám tak klidně stát, že zákazník, kterému jste aplikaci prodali si bude po roce stěžovat, že mu aplikace nefunguje a bude to jen z důvodu ukončení platnosti certifikátu. Budu tedy předpokládat, že budete assembly podepisovat klíčem .snk z VS/SDK. Aby bylo možné podvrhnout knihovnu referencovanou vaší aplikací, musela by tato knihovna být podepsaná stejným silným názvem což je prakticky nemožné, protože pro podepsání je nutné mít soukromou část klíče, kterou má pouze autor. Ještě by bylo dobré poznamenat, že pokud vaše aplikace referencuje knihovnu podepsanou silným názvem, musí být vaše aplikace rovněž podepsaná silným názvem.
Až do vydání .NET Frameworku 3.5 Service Pack 1 to fungovalo tak, že runtime CLR kontroloval hash všech zaváděných assembly a pokud tento hash neodpovídal, CLR nedovolilo assembly načíst. V Service Pack 1 tuto kontrolu omezili pouze na assembly pocházející z nedůvěryhodných umístění (Internet, LAN). Sám jsem narazil na tento problém, který je včetně řešení diskutován zde.
Pokud je tedy zapnuto ověřování a někdo změní ve vaší assembly jediný bit, CLR to pozná a změněnou assembly nedovolí načíst. Vytvořte si tedy svůj pár klíčů (návodů jak to udělat je na MSDN i jinde nepřeberné množství) a tím podepisujte všechny svoje projekty.
Ukázková signatura assembly podepsané klíčem snk (všimněte si hodnoty PublicKeyToken, což je právě SHA hash veřejné části klíče snk):
OL.Licensing, Version=3.0.4217.28505, Culture=neutral, PublicKeyToken=fa9d171f092a4ca1
Implementace licenčního mechanizmu
Poslední části v ochraně softwaru je implementace samotného licenčního mechanizmu. Pokud je vaše aplikace komerční, nebo nechcete, aby se nekontrolovaně šířila, měli byste takový mechanizmus určitě implementovat. Existují již hotová API pro tyto účely, nebo pokud jste dobří, můžete se pokusit napsat vlastní. Je potřeba brát na vědomí všechny výše uvedené faktory a také způsob použití aplikace. Pokud například bude aplikace používána pouze na jednom počítači, můžete licenci vázat na systémový disk, pokud bude potřeba používat aplikaci na více počítačích, můžete licenci vázat na disk USB Flash, nebo vytvořit licenci síťovou. Vždy se zkuste vžít do role uživatele aplikace a představit si, jestli pro něho nebude konkrétní typ licence otravný nebo nevyhovující. Já jsem ve svém licenčním API zvolil cestu licence vázané na systémový disk, nebo na disk USB Flash pro mobilní uživatele. V obou případech mohu navíc licenci omezit platností na určitou dobu a mnoha dalšími praktickými věcmi. Licenci mám ve formátu XML takže je snadno rozšiřitelná a digitálně podepsanou, což zabraňuje její neoprávněné modifikaci.
Doufám, že tento článek osvětlil alespoň základní principy ochrany software a detaily je možné řešit v případné diskusi komentáři.