Bitte machen Sie Ihre Sprache für Computer-Sicherheitsleute analysierbar / überprüfbar.
Sicherheitsleute müssen in der Lage sein, Sicherheitslücken in einem Programm zu finden, bevor es ausgeliefert wird. Im Idealfall werden wir frühzeitig angerufen und können die Codebasis während ihrer Entwicklung kommentieren, aber oft nicht.
Wenn eine neue Version der Sprache oder der Kernbibliotheken herauskommt, sind Dinge, die zuvor sicher waren, möglicherweise nicht mehr:
- Bibliotheken können leistungsfähiger werden: zB URL-Bibliothek unterstützt jetzt
javascript:
- Möglicherweise gibt es neue Möglichkeiten, Zeichenfolgen oder Bytes in Code zu konvertieren: z. B.
eval
oder Deserialisierungsbibliotheken
- Techniken zur Sprachreflexion können leistungsfähiger werden: z. B. die Darstellung lokaler Variablen
Jede dieser Änderungen kann die Anzahl der missbräuchlichen Berechtigungen eines Programms erhöhen. Da sich jedoch die Anzahl der vom Programm verwendeten Berechtigungen (im Umgang mit nicht böswilligen Clients) nicht geändert hat, ist es für Sicherheitsleute schwierig, dies ohne großen Aufwand herauszufinden erneutes Audit.
Denken Sie also bitte an uns, wenn Sie die Sprache entwerfen und versionieren. Nachfolgend einige Tipps:
Definieren Sie einige Grundelemente, in die ein Programm zerlegt werden kann.
HTML5 ist auf diese Weise besonders schlecht. Sie haben offensichtlich viel über Sicherheit nachgedacht und haben einige sehr kluge Leute, aber anstatt neue Programmelemente wie alte zu spezifizieren <video>
oder eine gemeinsame Abstraktion zu schaffen, für die sowohl neue <video>
als auch alte <img>
spezifiziert werden können, <video>
ist dies noch nicht der Fall ein weiteres einmaliges Programmelement mit eigenen Sicherheitsfolgen.
Machen Sie Ihre Sprache für statische Analysen zugänglich (auch wenn sie nicht statisch geschrieben ist).
Sicherheitsleute verwenden häufig statische Analysen, um Muster zu finden und Teile eines Programms auszuschließen, damit sie sich auf die wirklich kniffligen Dinge konzentrieren können.
Es sollte offensichtlich sein, welche Bezeichner lokale Variablen sind und welche nicht.
Machen Sie zum Beispiel nicht den gleichen Fehler wie bei alten Versionen von JavaScript, bei denen nicht festgestellt werden konnte, ob x
es sich im Folgenden um eine lokale Variablenreferenz handelt (gemäß einer wörtlichen Lesart einer alten Version der Spezifikation):
if (Math.random() > 0.5) {
Object.prototype.x = 0;
}
function f() {
var x = 1;
(function () {
alert(x); // Might alert 0, might alert 1.
})();
}
Lassen Sie zerlegbare Sicherheit zu
Viele sichere Systeme basieren auf einem sicheren Kernel, der die Sicherheitseigenschaften beibehält, so dass sich die Sicherheitsleute darauf konzentrieren können, eine kleine Menge Code zu analysieren und die meisten Programmierer von nervigen, pedantischen und paranoiden Sicherheitsleuten zu befreien .
Es sollte möglich sein, einen solchen Kernel in Ihrer Sprache zu schreiben. Wenn eine der Sicherheitseigenschaften Ihrer Sprache ist, dass nur eine bestimmte Teilmenge von URLs abgerufen wird, können die Kernel-Writer dann etwas tun, um alle URLs, die über ihren Code abgerufen werden, zu kanalisieren? Oder können statische Build-Prüfungen (wie das Betrachten von Importen) die gleiche Funktion erfüllen.
Einige Sprachen wie Newspeak verwenden ein Objektfähigkeitsmodell. Das ist großartig und eine großartige Möglichkeit, um zerlegbare Sicherheit zu erhalten.
Wenn Sie dies jedoch nicht tun können, können Sie einen erheblichen Nutzen daraus ziehen, das Moduldiagramm zu einem statisch auswertbaren Artefakt zu machen. Wenn ich nachweisen kann, dass ein Modul das Datei-E / A-Modul nicht erreichen kann (außer durch Aufrufen von Code in einem Modul im TCB), kann ich ganze Klassen von Problemen von diesem Modul ausschließen.
Beschränken Sie die Autorität eingebetteter Skriptsprachen
Viele nützliche Systeme sind als statischer Kern organisiert, der eine Menge in dynamischen (sogar funktionalen) Sprachen geschriebenen Codes anstößt.
Durch das Einbetten von Skriptsprachen kann ein System erheblich erweitert werden.
Eine Skriptsprache sollte jedoch nicht die volle Berechtigung der VM besitzen.
Wenn Sie eingebettete Skriptsprachen zulassen, können Sie dem Aufrufer die Einschränkung der von ihm ausgeführten Aktionen erleichtern. Ein Objektfähigkeitsmodell (siehe Kommentar zu Newspeak oben) ist hier sehr angebracht; Wenn Sie also Code in einer Skriptsprache auswerten, muss der Aufrufer den auszuführenden Code und alle globalen Variablen für diesen Code übergeben.
Behandle dich eval
als eine Sprache, die sich selbst als Skriptsprache einbettet
Wenn Ihre Sprache einen eigenen Compiler aufrufen kann, um eine Zeichenfolge in Code umzuwandeln, können Sie zulassen, dass sie wie jede eingebettete Skriptsprache in einer Sandbox gespeichert wird.
Verwenden Sie ein einfaches Parallelitätsmodell
Wir Sicherheitsleute müssen uns nicht um die Rennbedingungen kümmern, wenn wir herausfinden wollen, ob eine Sicherheitseigenschaft erhalten bleibt.
Bitte ziehen Sie Alternativen zum Threading in Betracht, bevor Sie sich für Threads entscheiden. Dies ist eine fast unmöglich zu sichernde Standardoption.
Eine einfache ist die Parallelität von Ereignisschleifen, wie sie in E, Verilog und JavaScript zu finden ist.
Fördern Sie nicht das Zitieren von Verwirrung
Einige Sprachen sind Klebesprachen und es kommt vor, dass sie sich mit Zeichenfolgen in vielen verschiedenen Sprachen befassen.
Beispielsweise setzt JavaScript häufig Zeichenfolgen aus HTML, CSS, XML, JSON und sogar JavaScript zusammen. Für Programmierer ist es sehr schwierig, sich daran zu erinnern, Klartext-Strings richtig zu codieren, wenn sie zu Strings in anderen Sprachen kombiniert werden. Daher gibt es in JS-Programmen, wie es nicht überraschend ist, alle Arten von Problemen mit Zitaten: XSS ist das Schlimmste.
Wenn Sie Funktionen zum Erstellen von Zeichenfolgen verwenden möchten, versuchen Sie, die Sicherheitslast des Programmierers zu verringern. DSLs, hygienische Makros und eingebettete Templatensprachen können eine großartige Möglichkeit sein, dies zu tun, indem der Aufwand für einen ordnungsgemäßen Fluchtweg zu Bibliotheks- oder Sprachentwicklern und weg vom Endentwickler verlagert wird.