637 lines
23 KiB
XML
637 lines
23 KiB
XML
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
|
|
<!--
|
|
The FreeBSD Documentation Project
|
|
The FreeBSD German Documentation Project
|
|
|
|
$FreeBSD$
|
|
$FreeBSDde: de-docproj/books/developers-handbook/secure/chapter.sgml,v 1.16 2010/12/18 13:28:29 jkois Exp $
|
|
basiert auf: 1.30
|
|
-->
|
|
|
|
<chapter id="secure">
|
|
<chapterinfo>
|
|
<authorgroup>
|
|
<author>
|
|
<firstname>Murray</firstname>
|
|
<surname>Stokely</surname>
|
|
<contrib>Contributed by </contrib>
|
|
</author>
|
|
</authorgroup>
|
|
<authorgroup>
|
|
<author>
|
|
<firstname>Hagen</firstname>
|
|
<surname>Kühl</surname>
|
|
<contrib>Übersetzt von </contrib>
|
|
</author>
|
|
</authorgroup>
|
|
</chapterinfo>
|
|
|
|
<title>Sicheres Programmieren</title>
|
|
|
|
<sect1 id="secure-synopsis">
|
|
<title>Zusammenfassung</title>
|
|
|
|
<para>Dieses Kapitel beschreibt einige Sicherheitsprobleme, die
|
|
&unix;-Programmierer seit Jahrzehnten quälen, und
|
|
inzwischen verfügbare Werkzeuge, die Programmierern helfen,
|
|
Sicherheitslücken in ihrem Quelltext zu vermeiden.</para>
|
|
</sect1>
|
|
|
|
<sect1 id="secure-philosophy">
|
|
<title>Methoden des sicheren Entwurfs</title>
|
|
|
|
<para>Sichere Anwendungen zu schreiben erfordert eine sehr
|
|
skeptische und pessimistische Lebenseinstellung. Anwendungen
|
|
sollten nach dem Prinzip der <quote>geringsten
|
|
Privilegien</quote> ausgeführt werden, sodass kein Prozess
|
|
mit mehr als dem absoluten Minimum an Zugriffsrechten arbeitet,
|
|
die er zum Erfüllen seiner Aufgabe benötigt. Wo es
|
|
möglich ist, sollte Quelltext, der bereits
|
|
überprüft wurde, wiederverwendet werden, um
|
|
häufige Fehler, die andere schon korrigiert haben, zu
|
|
vermeiden.</para>
|
|
|
|
<para>Eine der Stolperfallen der &unix;-Umgebung ist, dass es
|
|
sehr einfach ist Annahmen über die Konsistenz der Umgebung
|
|
zu machen. Anwendungen sollten Nutzereingaben (in allen Formen)
|
|
niemals trauen, genauso wenig wie den System-Ressourcen,
|
|
der Inter-Prozess-Kommunikation oder dem zeitlichen Ablauf von
|
|
Ereignissen. &unix;-Prozesse arbeiten nicht synchron. Daher sind
|
|
logische Operationen selten atomar.</para>
|
|
</sect1>
|
|
|
|
<sect1 id="secure-bufferov">
|
|
<title>Puffer-Überläufe</title>
|
|
|
|
<para>Puffer-Überläufe gibt es schon seit den
|
|
Anfängen der Von-Neuman-Architektur <xref linkend="COD"/>.
|
|
|
|
<indexterm><primary>Puffer-Überlauf</primary></indexterm>
|
|
<indexterm><primary>Von-Neuman</primary></indexterm>
|
|
|
|
Sie erlangten zum ersten Mal durch den Internetwurm Morris im
|
|
Jahre 1988 öffentliche Bekanntheit. Unglücklicherweise
|
|
|
|
<indexterm><primary>Morris Internetwurm</primary></indexterm>
|
|
|
|
funktioniert der gleiche grundlegende Angriff noch heute. Die bei weitem
|
|
häufigste Form eines Puffer-Überlauf-Angriffs basiert darauf,
|
|
den Stack zu korrumpieren.</para>
|
|
|
|
<indexterm><primary>Stack</primary></indexterm>
|
|
<indexterm><primary>Arguments</primary></indexterm>
|
|
|
|
<para>Die meisten modernen Computer-Systeme verwenden einen
|
|
Stack, um Argumente an Prozeduren zu übergeben und
|
|
lokale Variablen zu speichern. Ein Stack ist ein
|
|
last-in-first-out-Puffer (LIFO) im hohen Speicherbereich
|
|
eines Prozesses. Wenn ein Programm eine Funktion
|
|
|
|
<indexterm><primary>LIFO</primary></indexterm>
|
|
<indexterm>
|
|
<primary>Prozessabbild</primary>
|
|
<secondary>Stack-Pointer</secondary>
|
|
</indexterm>
|
|
|
|
aufruft wird ein neuer "Stackframe" erzeugt. Dieser besteht aus
|
|
den Argumenten, die der Funktion übergeben wurden und
|
|
einem variabel grossem Bereich für lokale Variablen. Der
|
|
"Stack-Pointer" ist ein Register, dass die
|
|
|
|
<indexterm><primary>Stack-Frame</primary></indexterm>
|
|
<indexterm><primary>Stack-Pointer</primary></indexterm>
|
|
|
|
aktuelle Adresse der Stack-Spitze enthält.
|
|
Da sich dieser Wert oft ändert, wenn neue Werte
|
|
auf dem Stack abgelegt werden, bieten viele Implementierungen
|
|
einen "Frame-Pointer", der nahe am Anfang des Stack-Frames
|
|
liegt und es so leichter macht lokale Variablen relativ zum
|
|
aktuellen Stackframe zu adressieren. <xref linkend="COD"/>
|
|
Die Rücksprungadresse
|
|
|
|
<indexterm><primary>Frame-Pointer</primary></indexterm>
|
|
<indexterm>
|
|
<primary>Prozessabbild</primary>
|
|
<secondary>Frame-Pointer</secondary>
|
|
</indexterm>
|
|
<indexterm><primary>Rücksprungadresse</primary></indexterm>
|
|
<indexterm><primary>Stack-Überlauf</primary></indexterm>
|
|
|
|
der Funktionen werden ebenfalls auf dem Stack
|
|
gespeichert und das ist der Grund für
|
|
Stack-Überlauf-Exploits. Denn ein böswilliger Nutzer
|
|
kann die Rücksprungadresse der Funktion überschreiben
|
|
indem er eine lokale Variable in der Funktion
|
|
überlaufen lässt, wodurch es ihm möglich ist
|
|
beliebigen Code auszuführen.</para>
|
|
|
|
<para>Obwohl Stack-basierte Angriffe bei weitem die
|
|
Häufigsten sind, ist es auch möglich den Stack mit
|
|
einem Heap-basierten (malloc/free) Angriff zu
|
|
überschreiben.</para>
|
|
|
|
<para>Die C-Programmiersprache führt keine automatischen
|
|
Bereichsüberprüfungen bei Feldern oder Zeigern durch, wie
|
|
viele andere Sprachen das tun. Außerdem enthält
|
|
die C-Standardbibliothek eine Handvoll sehr
|
|
gefährlicher Funktionen.</para>
|
|
|
|
<informaltable frame="none" pgwide="1">
|
|
<tgroup cols="2">
|
|
<tbody>
|
|
<row>
|
|
<entry><function>strcpy</function>(char *dest, const
|
|
char *src)</entry>
|
|
<entry><simpara>Kann den Puffer dest überlaufen
|
|
lassen</simpara></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><function>strcat</function>(char *dest, const
|
|
char *src)</entry>
|
|
<entry><simpara>Kann den Puffer dest überlaufen
|
|
lassen</simpara></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><function>getwd</function>(char *buf)</entry>
|
|
<entry><simpara>Kann den Puffer buf überlaufen
|
|
lassen</simpara></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><function>gets</function>(char *s)</entry>
|
|
<entry><simpara>Kann den Puffer s überlaufen
|
|
lassen</simpara></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><function>[vf]scanf</function>(const char
|
|
*format, ...)</entry>
|
|
<entry><simpara>Kann sein Argument überlaufen
|
|
lassen</simpara></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><function>realpath</function>(char *path,
|
|
char resolved_path[])</entry>
|
|
<entry><simpara>Kann den Puffer path überlaufen
|
|
lassen</simpara></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><function>[v]sprintf</function>(char *str,
|
|
const char *format, ...)</entry>
|
|
<entry><simpara>Kann den Puffer str überlaufen
|
|
lassen</simpara></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
|
|
<sect2>
|
|
<title>Puffer-Überlauf Beispiel</title>
|
|
|
|
<para>Das folgende Quellcode-Beispiel enthält einen
|
|
Puffer-Überlauf, der darauf ausgelegt ist die
|
|
Rücksprungadresse zu überschreiben und die
|
|
Anweisung direkt nach dem Funktionsaufruf zu
|
|
überspringen. (Inspiriert durch
|
|
<xref linkend="Phrack"/>)</para>
|
|
|
|
<programlisting>#include <stdio.h>
|
|
|
|
void manipulate(char *buffer) {
|
|
char newbuffer[80];
|
|
strcpy(newbuffer,buffer);
|
|
}
|
|
|
|
int main() {
|
|
char ch,buffer[4096];
|
|
int i=0;
|
|
|
|
while ((buffer[i++] = getchar()) != '\n') {};
|
|
|
|
i=1;
|
|
manipulate(buffer);
|
|
i=2;
|
|
printf("The value of i is : %d\n",i);
|
|
return 0;
|
|
}</programlisting>
|
|
|
|
<para>Betrachten wir nun, wie das Speicherabbild dieses
|
|
Prozesses aussehen würde, wenn wir 160 Leerzeichen
|
|
in unser kleines Programm eingeben, bevor wir Enter
|
|
drücken.</para>
|
|
|
|
<para>[XXX figure here!]</para>
|
|
|
|
<para>Offensichtlich kann man durch böswilligere Eingaben
|
|
bereits kompilierten Programmtext ausführen (wie z.B.
|
|
exec(/bin/sh)).</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Puffer-Überläufe vermeiden</title>
|
|
|
|
<para>Die direkteste Lösung, um
|
|
Stack-Überläufe zu vermeiden, ist immer
|
|
grössenbegrenzten Speicher und String-Copy-Funktionen
|
|
zu verwenden.
|
|
<function>strncpy</function> und <function>strncat</function>
|
|
sind Teil der C-Standardbibliothek.
|
|
|
|
<indexterm>
|
|
<primary>Zeichenketten-Kopierfunktioen</primary>
|
|
<secondary>strncpy</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>Zeichenketten-Kopierfunktionen</primary>
|
|
<secondary>strncat</secondary>
|
|
</indexterm>
|
|
|
|
Diese Funktionen akzeptieren einen Längen-Parameter. Dieser
|
|
Wert sollte nicht größer sein als die Länge
|
|
des Zielpuffers. Die Funktionen kopieren dann bis zu
|
|
`length' Bytes von der Quelle zum Ziel. Allerdings gibt es
|
|
einige Probleme. Keine der Funktionen garantiert, dass
|
|
die Zeichenkette NUL-terminiert ist, wenn die
|
|
Größe
|
|
|
|
<indexterm><primary>NUL-Terminierung</primary></indexterm>
|
|
|
|
des Eingabepuffers so groß ist wie das Ziel.
|
|
Außerdem wird der Parameter length zwischen strncpy
|
|
und strncat inkonsistent definiert, weshalb Programmierer
|
|
leicht bezüglich der korrekten Verwendung durcheinander
|
|
kommen können. Weiterhin gibt es einen spürbaren
|
|
Leistungsverlust im Vergleich zu
|
|
<function>strcpy</function>, wenn eine kurze Zeichenkette in
|
|
einen großen Puffer kopiert wird. Denn
|
|
<function>strncpy</function> fült den Puffer bis zur
|
|
angegebenen Länge mit NUL auf.
|
|
</para>
|
|
|
|
<para>In OpenBSD wurde eine weitere Möglichkeit zum
|
|
|
|
<indexterm><primary>OpenBSD</primary></indexterm>
|
|
|
|
kopieren von Speicherbereichen implementiert, die dieses
|
|
Problem umgeht. Die Funktionen <function>strlcpy</function>
|
|
und <function>strlcat</function> garantieren, dass das Ziel
|
|
immer NUL-terminiert wird, wenn das Argument length ungleich
|
|
null ist. Für weitere Informationen über diese
|
|
Funktionen lesen Sie bitte <xref linkend="OpenBSD"/>. Die
|
|
OpenBSD-Funktionen <function>strlcpy</function> und
|
|
<function>strlcat</function> sind seit Version 3.3 auch in
|
|
FreeBSD verfügbar.</para>
|
|
|
|
<indexterm>
|
|
<primary>Zeichenketten-Kopierfunktionen</primary>
|
|
<secondary>strlcpy</secondary>
|
|
</indexterm>
|
|
|
|
<indexterm>
|
|
<primary>Zeichenketten-Kopierfunktionen</primary>
|
|
<secondary>strlcat</secondary>
|
|
</indexterm>
|
|
|
|
<sect3>
|
|
<title>Compiler-basierte Laufzeitüberprüfung
|
|
von Grenzen</title>
|
|
|
|
<indexterm>
|
|
<primary>Prüfung von Grenzen</primary>
|
|
<secondary>Compiler-basiert</secondary>
|
|
</indexterm>
|
|
|
|
<para>Unglücklicherweise gibt es immer noch sehr viel
|
|
Quelltext, der allgemein verwendet wird und blind Speicher
|
|
umherkopiert, ohne eine der gerade besprochenen Funktionen,
|
|
die Begrenzungen unterstützen, zu verwenden.
|
|
Glücklicherweise gibt es einen Weg, um solche Angriffe zu
|
|
verhindern - Überprüfung der Grenzen zur Laufzeit, die in
|
|
verschiedenen C/C++ Compilern eingebaut ist.</para>
|
|
|
|
<indexterm><primary>ProPolice</primary></indexterm>
|
|
<indexterm><primary>StackGuard</primary></indexterm>
|
|
<indexterm><primary>GCC</primary></indexterm>
|
|
|
|
<para>ProPolice ist eine solche Compiler-Eigenschaft und ist in den
|
|
&man.gcc.1; Versionen 4.1 und höher integriert. Es ersetzt und
|
|
erweitert die &man.gcc.1; StackGuard-Erweiterung von
|
|
früher.</para>
|
|
|
|
<para>ProPolice schützt gegen stackbasierte
|
|
Pufferüberläufe und andere Angriffe durch das Ablegen von
|
|
Pseudo-Zufallszahlen in Schlüsselbereichen des Stacks bevor es
|
|
irgendwelche Funktionen aufruft. Wenn eine Funktion beendet wird,
|
|
werden diese <quote>Kanarienvögel</quote> überprüft
|
|
und wenn festgestellt wird, dass diese verändert wurden wird das
|
|
Programm sofort abgebrochen. Dadurch wird jeglicher Versuch, die
|
|
Rücksprungadresse oder andere Variablen, die auf dem Stack
|
|
gespeichert werden, durch die Ausführung von Schadcode zu
|
|
manipulieren, nicht funktionieren, da der Angreifer auch die
|
|
Pseudo-Zufallszahlen unberührt lassen müsste.</para>
|
|
|
|
<indexterm><primary>Puffer-Überlauf</primary></indexterm>
|
|
|
|
<para>Ihre Anwendungen mit ProPolice neu zu kompilieren ist
|
|
eine effektive Maßnahme, um sie vor den meisten
|
|
Puffer-Überlauf-Angriffen zu schützen, aber die
|
|
Programme können noch immer kompromittiert werden.</para>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title>Bibliotheks-basierte Laufzeitüberprüfung
|
|
von Grenzen</title>
|
|
|
|
<indexterm>
|
|
<primary>Prüfung von Grenzen</primary>
|
|
<secondary>Bibliotheks-basiert</secondary>
|
|
</indexterm>
|
|
|
|
<para>Compiler-basierte Mechanismen sind bei Software,
|
|
die nur im Binärformat vertrieben wird, und die somit
|
|
nicht neu kompiliert werden kann völlig nutzlos.
|
|
Für diesen Fall gibt es einige Bibliotheken, welche
|
|
die unsicheren Funktionen der C-Bibliothek
|
|
(<function>strcpy</function>, <function>fscanf</function>,
|
|
<function>getwd</function>, etc..) neu implementieren und
|
|
sicherstellen, dass nicht hinter den Stack-Pointer
|
|
geschrieben werden kann.</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><simpara>libsafe</simpara></listitem>
|
|
<listitem><simpara>libverify</simpara></listitem>
|
|
<listitem><simpara>libparanoia</simpara></listitem>
|
|
</itemizedlist>
|
|
|
|
<para>Leider haben diese Bibliotheks-basierten
|
|
Verteidigungen mehrere Schwächen. Diese Bibliotheken
|
|
schützen nur vor einer kleinen Gruppe von
|
|
Sicherheitslücken und sie können das
|
|
eigentliche Problem nicht lösen. Diese
|
|
Maßnahmen können versagen, wenn die Anwendung
|
|
mit -fomit-frame-pointer kompiliert wurde.
|
|
Außerdem kann der Nutzer die Umgebungsvariablen
|
|
LD_PRELOAD und LD_LIBRARY_PATH überschreiben oder
|
|
löschen.</para>
|
|
</sect3>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 id="secure-setuid">
|
|
<title>SetUID-Themen</title>
|
|
|
|
<indexterm><primary>seteuid</primary></indexterm>
|
|
|
|
<para>Es gibt zu jedem Prozess mindestens sechs verschiedene
|
|
IDs, die diesem zugeordnet sind. Deshalb müssen Sie
|
|
sehr vorsichtig mit den Zugriffsrechten sein, die Ihr Prozess
|
|
zu jedem Zeitpunkt besitzt. Konkret bedeutet dass, das alle
|
|
seteuid-Anwendungen ihre Privilegien abgeben sollten, sobald
|
|
sie diese nicht mehr benötigen.</para>
|
|
|
|
<indexterm>
|
|
<primary>Benutzer-IDs</primary>
|
|
<secondary>reale Benutzer-ID</secondary>
|
|
</indexterm>
|
|
<indexterm>
|
|
<primary>Benutzer-IDs</primary>
|
|
<secondary>effective Benutzer-ID</secondary>
|
|
</indexterm>
|
|
|
|
<para>Die reale Benutzer-ID kann nur von einem
|
|
Superuser-Prozess geändert werden. Das Programm
|
|
<application>login</application> setzt sie, wenn sich ein
|
|
Benutzer am System anmeldet, und sie wird nur selten
|
|
geändert.</para>
|
|
|
|
<para>Die effektive Benutzer-ID wird von der Funktion
|
|
<function>exec()</function> gesetzt, wenn ein Programm
|
|
das seteuid-Bit gesetzt hat. Eine Anwendung kann
|
|
<function>seteuid()</function> jederzeit aufrufen, um die
|
|
effektive Benutzer-ID entweder auf die reale Benutzer-ID oder
|
|
die gespeicherte set-user-ID zu setzen. Wenn eine der
|
|
<function>exec()</function>-Funktionen die effektive
|
|
Benutzer-ID setzt, wird der vorherige Wert als
|
|
gespeicherte set-user-ID abgelegt.</para>
|
|
</sect1>
|
|
|
|
<sect1 id="secure-chroot">
|
|
<title>Die Umgebung ihrer Programme einschränken</title>
|
|
|
|
<indexterm><primary>chroot()</primary></indexterm>
|
|
|
|
<para>Die herkömmliche Methode, um einen Prozess
|
|
einzuschränken, besteht in dem Systemaufruf
|
|
<function>chroot()</function>. Dieser Aufruf
|
|
ändert das Wurzelverzeichnis, auf das sich alle
|
|
Pfadangaben des Prozesses und jegliche Kind-Prozesse beziehen.
|
|
Damit dieser Systemaufruf gelingt, muss der Prozess
|
|
Ausführungsrechte (Durchsuchungsrechte) für das
|
|
Verzeichnis haben, auf das er sich bezieht. Die neue Umgebung
|
|
wird erst wirksam, wenn Sie mittels
|
|
<function>chdir()</function> in Ihre neue Umgebung wechseln.
|
|
Es sollte erwähnt werden, dass ein Prozess recht einfach
|
|
aus der chroot-Umgebung ausbrechen kann, wenn er root-Rechte
|
|
besitzt. Das kann man erreichen, indem man Gerätedateien
|
|
anlegt, um Kernel-Speicher zu lesen, oder indem man einen
|
|
Debugger mit einem Prozess außerhalb seiner
|
|
&man.chroot.8;-Umgebung verbindet, oder auf viele andere
|
|
kreative Wege.</para>
|
|
|
|
<para>Das Verhalten des Systemaufrufs
|
|
<function>chroot()</function> kann durch die
|
|
kern.chroot.allow_open_directories
|
|
<command>sysctl</command>-Variable beeinflusst werden. Wenn
|
|
diese auf 0 gesetzt ist, wird <function>chroot()</function>
|
|
mit EPERM fehlschlagen, wenn irgendwelche Verzeichnisse
|
|
geöffnet sind. Wenn die Variable auf den Standardwert 1
|
|
gesetzt ist, wird <function>chroot()</function> mit EPERM
|
|
fehlschlagen, wenn irgendwelche Verzeichnisse geöffnet
|
|
sind und sich der Prozess bereits in einer
|
|
<function>chroot()</function>-Umgebung befindet. Bei jedem
|
|
anderen Wert wird die Überprüfung auf
|
|
geöffnete Verzeichnisse komplett umgangen.</para>
|
|
|
|
<sect2>
|
|
<title>Die Jail-Funktionalität in FreeBSD</title>
|
|
|
|
<indexterm><primary>Jail</primary></indexterm>
|
|
|
|
<para>Das Konzept einer Jail (Gefängnis) erweitert
|
|
<function>chroot()</function>, indem es die Macht des
|
|
Superusers einschränkt, um einen echten 'virtuellen
|
|
Server' zu erzeugen. Wenn ein solches Gefängnis einmal
|
|
eingerichtet ist, muss die gesamte Netzwerkkommunikation
|
|
über eine bestimmte IP-Adresse erfolgen und die
|
|
"root-Privilegien" innerhalb der Jail sind sehr stark
|
|
eingeschränkt.</para>
|
|
|
|
<para>Solange Sie sich in einer Jail befinden, werden alle
|
|
Tests auf Superuser-Rechte durch den Aufruf von
|
|
<function>suser()</function> fehlschlagen. Allerdings wurden
|
|
einige Aufrufe von <function>suser()</function>
|
|
abgeändert, um die neue
|
|
<function>suser_xxx()</function>-Schnittstelle zu
|
|
implementieren. Diese Funktion ist dafür verantwortlich,
|
|
festzustellen, ob bestimmte Superuser-Rechte einem
|
|
eingesperrten Prozess zur Verfügung stehen.</para>
|
|
|
|
<para>Ein Superuser-Prozess innerhalb einer Jail darf
|
|
folgendes:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<simpara>Berechtigungen verändern mittels:
|
|
<function>setuid</function>,
|
|
<function>seteuid</function>,
|
|
<function>setgid</function>,
|
|
<function>setegid</function>,
|
|
<function>setgroups</function>,
|
|
<function>setreuid</function>,
|
|
<function>setregid</function>,
|
|
<function>setlogin</function></simpara>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<simpara>Ressourcenbegrenzungen setzen mittels
|
|
<function>setrlimit</function></simpara>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<simpara>Einige sysctl-Variablen (kern.hostname)
|
|
verändern</simpara>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<simpara><function>chroot()</function></simpara>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<simpara>Ein Flag einer vnode setzen:
|
|
<function>chflags</function>,
|
|
<function>fchflags</function></simpara>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<simpara>Attribute einer vnode setzen wie Dateiberechtigungen,
|
|
Eigentümer, Gruppe, Größe, Zugriffszeit
|
|
und Modifikationszeit</simpara>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<simpara>Binden eines Prozesses an einen öffentlichen
|
|
privilegierten Port (ports < 1024)</simpara>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para><function>Jail</function>s sind ein mächtiges
|
|
Werkzeug, um Anwendungen in einer sicheren Umgebung
|
|
auszuführen, aber sie haben auch ihre Nachteile.
|
|
Derzeit wurden die IPC-Mechanismen noch nicht an
|
|
<function>suser_xxx</function> angepasst, so dass Anwendungen
|
|
wie MySQL nicht innerhalb einer Jail ausgeführt werden
|
|
können. Der Superuser-Zugriff hat in einer Jail nur eine
|
|
sehr eingeschränkte Bedeutung, aber es gibt keine
|
|
Möglichkeit zu definieren was
|
|
"sehr eingeschränkt" heißt.</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>&posix;.1e Prozess Capabilities</title>
|
|
|
|
<indexterm><primary>POSIX.1e Process
|
|
Capabilities</primary></indexterm>
|
|
<indexterm><primary>TrustedBSD</primary></indexterm>
|
|
|
|
<para>&posix; hat einen funktionalen Entwurf (Working Draft)
|
|
herausgegeben, der Ereignisüberprüfung,
|
|
Zugriffskontrolllisten, feiner einstellbare Privilegien,
|
|
Informationsmarkierung und verbindliche Zugriffskontrolle
|
|
enthält.</para>
|
|
|
|
<para>Dies ist im Moment in Arbeit und das Hauptziel des <ulink
|
|
url="http://www.trustedbsd.org/">TrustedBSD</ulink>-Projekts.
|
|
Ein Teil der bisherigen Arbeit wurde in &os.current;
|
|
übernommen (cap_set_proc(3)).</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 id="secure-trust">
|
|
<title>Vertrauen</title>
|
|
|
|
<para>Eine Anwendung sollte niemals davon ausgehen, dass
|
|
irgendetwas in der Nutzerumgebung vernünftig ist.
|
|
Das beinhaltet (ist aber sicher nicht darauf
|
|
beschränkt): Nutzereingaben, Signale,
|
|
Umgebungsvariablen, Ressourcen, IPC, mmaps, das
|
|
Arbeitsverzeichnis im Dateisystem, Dateideskriptoren,
|
|
die Anzahl geöffneter Dateien, etc..</para>
|
|
|
|
<indexterm><primary>positive Filterung</primary></indexterm>
|
|
<indexterm><primary>Datenvalidierung</primary></indexterm>
|
|
|
|
<para>Sie sollten niemals annehmen, dass Sie jede Art von
|
|
inkorrekten Eingaben abfangen können, die ein Nutzer
|
|
machen kann. Stattdessen sollte Ihre Anwendung positive
|
|
Filterung verwenden, um nur eine bestimmte Teilmenge an
|
|
Eingaben zuzulassen, die Sie für sicher halten.
|
|
Ungeeignete Datenüberprüfung ist die Ursache
|
|
vieler Exploits, besonders für CGI-Skripte im Internet.
|
|
Bei Dateinamen müssen Sie besonders vorsichtig sein,
|
|
wenn es sich um Pfade ("../", "/"), symbolische
|
|
Verknüpfungen und Shell-Escape-Sequenzen handelt.</para>
|
|
|
|
<indexterm><primary>Perl Taint-Modus</primary></indexterm>
|
|
|
|
<para>Perl bietet eine wirklich coole Funktion, den sogenannten
|
|
"Taint"-Modus, der verwendet werden kann, um zu verhindern,
|
|
dass Skripte Daten, die von außerhalb des Programmes
|
|
stammen, auf unsichere Art und Weise verwenden. Dieser
|
|
Modus überprüft Kommandozeilenargumente,
|
|
Umgebungsvariablen, Lokalisierungsinformationen, die
|
|
Ergebnisse von Systemaufrufen
|
|
(<function>readdir()</function>,
|
|
<function>readlink()</function>,
|
|
<function>getpwxxx()</function>)
|
|
und alle Dateieingaben.</para>
|
|
</sect1>
|
|
|
|
<sect1 id="secure-race-conditions">
|
|
<title>Race-Conditions</title>
|
|
|
|
<para>Eine Race-Condition ist ein unnormales Verhalten, das von
|
|
einer unerwarteten Abhängigkeit beim Timing von Ereignissen
|
|
verursacht wird. Mit anderen Worten heißt das, ein
|
|
Programmierer nimmt irrtümlicher Weise an, dass ein
|
|
bestimmtes Ereignis immer vor einem anderen stattfindet.</para>
|
|
|
|
<indexterm><primary>Race-Conditions</primary>
|
|
<secondary>Signale</secondary></indexterm>
|
|
|
|
<indexterm><primary>Race-Conditions</primary>
|
|
<secondary>Zugriffsprüfungen</secondary></indexterm>
|
|
|
|
<indexterm><primary>Race-Conditions</primary>
|
|
<secondary>Öffnen von Dateien</secondary></indexterm>
|
|
|
|
<para>Einige der häufigsten Ursachen für
|
|
Race-Conditions sind Signale, Zugriffsprüfungen und das
|
|
Öffnen von Dateien. Signale sind von Natur aus
|
|
asynchrone Ereignisse, deshalb ist besondere Vorsicht im
|
|
Umgang damit geboten. Das Prüfen des Zugriffs mittels
|
|
der Aufrufe <function>access(2)</function> gefolgt von
|
|
<function>open(2)</function> ist offensichtlich nicht atomar.
|
|
Benutzer können zwischen den beiden Aufrufen Dateien
|
|
verschieben. Stattdessen sollten privilegierte Anwendungen
|
|
<function>seteuid()</function> direkt gefolgt von
|
|
<function>open()</function> aufrufen. Auf die gleiche Art
|
|
sollte eine Anwendung immer eine korrekte Umask vor dem
|
|
Aufruf von <function>open()</function> setzen, um
|
|
störende Aufrufe von <function>chmod()</function> zu
|
|
umgehen.</para>
|
|
</sect1>
|
|
</chapter>
|