Rendi la tua lingua analizzabile / verificabile per gli addetti alla sicurezza del computer.
Gli addetti alla sicurezza devono essere in grado di trovare le vulnerabilità in un programma prima della spedizione. Idealmente, siamo chiamati in anticipo e possiamo commentare la base di codice mentre si sviluppa, ma spesso no.
Quando esce una nuova versione della lingua o delle librerie di base, le cose che erano precedentemente sicure potrebbero non essere più:
- le librerie possono diventare più potenti: ad esempio la libreria URL ora supporta
javascript:
- ci possono essere nuovi modi per convertire stringhe o byte in codice: ad esempio
eval
o librerie di deserializzazione
- le tecniche di riflessione del linguaggio possono diventare più potenti: es. esporre variabili locali
Ognuna di queste modifiche può aumentare la quantità di autorità abusabile di un programma, ma poiché la quantità di autorità che il programma utilizza (quando si tratta di client non dannosi) non è cambiata, le persone di sicurezza sono difficili da capire senza un intenso nuovo audit.
Quindi, ti preghiamo di pensarci quando progettiamo e verifichiamo la lingua. Di seguito sono riportati alcuni suggerimenti:
Definire alcune primitive in cui un programma può essere scomposto.
HTML5 è particolarmente dannoso in questo modo. Hanno ovviamente pensato molto alla sicurezza e hanno alcune persone molto intelligenti, ma invece di specificare nuovi elementi del programma come <video>
in termini di vecchi, o creare un'astrazione comune secondo cui sia <video>
vecchi che nuovi <img>
possono essere specificati in termini di, <video>
è ancora un altro elemento del programma una tantum con le sue conseguenze sulla sicurezza.
Rendi la tua lingua adatta all'analisi statica (anche se non tipizzata staticamente).
La gente della sicurezza spesso usa l'analisi statica per trovare schemi e per cercare di escludere parti di un programma in modo che possano concentrarsi su bit davvero complicati.
Dovrebbe essere ovvio quali identificatori sono variabili locali e quali no.
Ad esempio, non commettere lo stesso errore delle vecchie versioni di JavaScript che ha reso impossibile stabilire se x
si tratti di un riferimento alla variabile locale nel seguito (secondo una lettura letterale di una vecchia versione della specifica):
if (Math.random() > 0.5) {
Object.prototype.x = 0;
}
function f() {
var x = 1;
(function () {
alert(x); // Might alert 0, might alert 1.
})();
}
Consentire la sicurezza decomposibile
Molti sistemi sicuri sono progettati attorno a un kernel sicuro che preserva le proprietà di sicurezza, in modo che le persone di sicurezza possano concentrare i loro sforzi sull'analisi di una piccola quantità di codice e liberare la maggior parte dei programmatori dal dover affrontare gente di sicurezza {fastidiosa, pedante, paranoica} .
Dovrebbe essere possibile scrivere un tale kernel nella tua lingua. Se una delle proprietà di sicurezza della tua lingua è che verrà recuperato solo un determinato sottoinsieme di URL, gli autori del kernel possono fare qualcosa per incanalare tutto il recupero degli URL attraverso il loro codice? Oppure i controlli di build statici (come guardare le importazioni) possono svolgere la stessa funzione.
Alcuni linguaggi come Newspeak utilizzano un modello di funzionalità degli oggetti. È fantastico e un ottimo modo per ottenere una sicurezza scomponibile.
Ma se non riesci a farlo, rendere il grafico del modulo un artefatto staticamente analizzabile può offrirti un bel po 'di vantaggio. Se posso dimostrare che un modulo non può raggiungere il modulo I / O del file (tranne chiamando il codice in un modulo nel TCB), allora posso escludere intere classi di problemi da quel modulo.
Limitare l'autorità dei linguaggi di scripting incorporati
Molti sistemi utili sono organizzati come un nucleo statico che dà il via a molto codice scritto in linguaggi dinamici (anche funzionali).
E l'incorporamento dei linguaggi di scripting può rendere un sistema molto più estensibile.
Ma un linguaggio di scripting non dovrebbe avere la piena autorità della VM.
Se si sceglie di consentire i linguaggi di scripting incorporati, è facile per l'invocatore limitare ciò che possono fare. Un modello di funzionalità degli oggetti (vedi commento su Newspeak sopra) è molto appropriato qui; quindi quando valuta il codice in un linguaggio di scripting, il chiamante deve passare il codice per eseguire e tutte le variabili globali per quel codice.
Tratta eval
come un linguaggio che si incorpora come un linguaggio di scripting
Se la tua lingua è in grado di invocare il proprio compilatore per trasformare una stringa in codice, allora consenti che il sandbox sia lo stesso di qualsiasi altro linguaggio di scripting incorporato.
Utilizzare un semplice modello di concorrenza
A noi della sicurezza non piace preoccuparsi delle condizioni di gara quando si cerca di capire se una proprietà di sicurezza viene mantenuta.
Si prega di considerare le alternative al threading prima di stabilirsi sui thread come un'opzione predefinita quasi impossibile da proteggere.
Uno semplice è la concorrenza del ciclo di eventi come quella presente in E, Verilog e JavaScript.
Non incoraggiare a citare confusione
Alcune lingue sono lingue di colla e finiscono per gestire stringhe in molte lingue diverse.
Ad esempio, JavaScript spesso compone stringhe di HTML, CSS, XML, JSON e persino JavaScript. È molto difficile per i programmatori ricordare di codificare correttamente le stringhe di testo semplice quando le combinano per creare stringhe in altre lingue, quindi i programmi JS, ovviamente, hanno tutti i tipi di problemi di confusione citati: XSS è il peggiore.
Se si desidera includere funzionalità di composizione delle stringhe, provare a ridurre il carico di sicurezza del programmatore. DSL, macro igieniche e linguaggi di template incorporati possono essere un ottimo modo per farlo spostando l'onere di fuggire correttamente nella libreria o negli sviluppatori di lingue e allontanarsi dallo sviluppatore finale.