245 lines
6.4 KiB
HTML
245 lines
6.4 KiB
HTML
<HTML
|
|
><HEAD
|
|
><TITLE
|
|
>Specially Protect Secrets (Passwords and Keys) in User Memory</TITLE
|
|
><META
|
|
NAME="GENERATOR"
|
|
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK
|
|
REL="HOME"
|
|
TITLE="Secure Programming for Linux and Unix HOWTO"
|
|
HREF="index.html"><LINK
|
|
REL="UP"
|
|
TITLE="Special Topics"
|
|
HREF="special.html"><LINK
|
|
REL="PREVIOUS"
|
|
TITLE="Random Numbers"
|
|
HREF="random-numbers.html"><LINK
|
|
REL="NEXT"
|
|
TITLE="Cryptographic Algorithms and Protocols"
|
|
HREF="crypto.html"></HEAD
|
|
><BODY
|
|
CLASS="SECT1"
|
|
BGCOLOR="#FFFFFF"
|
|
TEXT="#000000"
|
|
LINK="#0000FF"
|
|
VLINK="#840084"
|
|
ALINK="#0000FF"
|
|
><DIV
|
|
CLASS="NAVHEADER"
|
|
><TABLE
|
|
SUMMARY="Header navigation table"
|
|
WIDTH="100%"
|
|
BORDER="0"
|
|
CELLPADDING="0"
|
|
CELLSPACING="0"
|
|
><TR
|
|
><TH
|
|
COLSPAN="3"
|
|
ALIGN="center"
|
|
>Secure Programming for Linux and Unix HOWTO</TH
|
|
></TR
|
|
><TR
|
|
><TD
|
|
WIDTH="10%"
|
|
ALIGN="left"
|
|
VALIGN="bottom"
|
|
><A
|
|
HREF="random-numbers.html"
|
|
ACCESSKEY="P"
|
|
>Prev</A
|
|
></TD
|
|
><TD
|
|
WIDTH="80%"
|
|
ALIGN="center"
|
|
VALIGN="bottom"
|
|
>Chapter 11. Special Topics</TD
|
|
><TD
|
|
WIDTH="10%"
|
|
ALIGN="right"
|
|
VALIGN="bottom"
|
|
><A
|
|
HREF="crypto.html"
|
|
ACCESSKEY="N"
|
|
>Next</A
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><HR
|
|
ALIGN="LEFT"
|
|
WIDTH="100%"></DIV
|
|
><DIV
|
|
CLASS="SECT1"
|
|
><H1
|
|
CLASS="SECT1"
|
|
><A
|
|
NAME="PROTECT-SECRETS"
|
|
></A
|
|
>11.4. Specially Protect Secrets (Passwords and Keys) in User Memory</H1
|
|
><P
|
|
>If your application must handle passwords or non-public keys
|
|
(such as session keys, private keys, or secret keys), try to hide them
|
|
and overwrite them immediately after using them so they have minimal exposure.</P
|
|
><P
|
|
>Systems such as Linux support the mlock() and mlockall() calls to
|
|
keep memory from being paged to disk (since someone might acquire the
|
|
kep later from the swap file).
|
|
Note that on Linux this is a privileged system call, which causes its
|
|
own issues (do I grant the program superuser privileges so it can call
|
|
mlock, if it doesn't need them otherwise?).</P
|
|
><P
|
|
>Also, if your program handles such secret values, be sure to disable creating
|
|
core dumps (via ulimit). Otherwise, an attacker may be able to halt the
|
|
program and find the secret value in the data dump.</P
|
|
><P
|
|
>Beware - normally processes can monitor other processes through
|
|
the calls for debuggers (e.g., via ptrace(2) and the /proc pseudo-filesystem)
|
|
[Venema 1996]
|
|
Kernels usually protect against these monitoring routines if the process is
|
|
setuid or setgid
|
|
(on the few ancient ones that don't, there really isn't a good way to
|
|
defend yourself other than upgrading).
|
|
Thus, if your process manages secret values, you probably should make it
|
|
setgid or setuid (to a different unprivileged group or user) to forceably
|
|
inhibit this kind of monitoring.
|
|
Unless you need it to be setuid, use setgid (since this grants fewer
|
|
privileges).</P
|
|
><P
|
|
>Then there's the problem of being able to actually overwrite the value, which
|
|
often becomes language and compiler specific.
|
|
In many languages, you need to make sure that you store
|
|
such information in mutable locations, and then overwrite those locations.
|
|
For example,
|
|
in Java, don't use the type String to store a password because Strings are
|
|
immutable (they will not be overwritten until garbage-collected and
|
|
then reused, possibly a far time in the future).
|
|
Instead, in Java use char[] to store a password, so it can be
|
|
immediately overwritten.
|
|
In Ada, use type String (an array of characters),
|
|
and not type Unbounded_String, to make sure
|
|
that you have control over the contents.</P
|
|
><P
|
|
>In many languages (including C and C++),
|
|
be careful that the compiler doesn't optimize away the "dead code"
|
|
for overwriting the value - since in this case it's not dead code.
|
|
Many compilers, including many C/C++ compilers, remove writes
|
|
to stores that are no longer used - this is often referred to as
|
|
"dead store removal."
|
|
Unfortunately, if the write is really to overwrite the value of a secret,
|
|
this means that code that appears to be correct will be silently discareded.
|
|
Ada provides the pragma Inspection_Point; place this after the
|
|
code erasing the memory, and that way you can be certain that
|
|
the object containing the secret will really be erased
|
|
(and that the the overwriting won't be optimized away).</P
|
|
><P
|
|
>A Bugtraq post by Andy Polyakov (November 7, 2002) reported that
|
|
the C/C++ compilers gcc version 3 or higher, SGI MIPSpro, and the Microsoft
|
|
compilers eliminated simple inlined calls to memset
|
|
intended to overwrite secrets.
|
|
This is allowed by the C and C++ standards.
|
|
Other C/C++ compilers (such as gcc less than version 3) preserved the inlined
|
|
call to memset at all optimization levels, showing that the issue
|
|
is compiler-specific.
|
|
Simply declaring that the destination data is volatile doesn't
|
|
help on all compilers; both the MIPSpro and Microsoft compilers
|
|
ignored simple "volatilization".
|
|
Simply "touching" the first byte of the secret data doesn't help either;
|
|
he found that the MIPSpro and GCC>=3 cleverly nullify only the first byte
|
|
and leave the rest intact (which is actually quite clever - the problem
|
|
is that the compiler's cleverness is interfering with our goals).
|
|
One approach that
|
|
seems to work on all platforms is to
|
|
write your own implementation of memset with internal "volatilization"
|
|
of the first argument (this code is based on a
|
|
<A
|
|
HREF="http://online.securityfocus.com/archive/82/298061/2002-10-27/2002-11-02/0"
|
|
TARGET="_top"
|
|
>workaround proposed by Michael Howard</A
|
|
>):
|
|
<TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
> void *guaranteed_memset(void *v,int c,size_t n)
|
|
{ volatile char *p=v; while (n--) *p++=c; return v; }</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
>
|
|
Then place this definition into an external file to force the function to
|
|
be external (define the function in a corresponding .h file, and #include
|
|
the file in the callers, as is usual).
|
|
This approach appears to be safe
|
|
at any optimization level (even if the function gets inlined).</P
|
|
></DIV
|
|
><DIV
|
|
CLASS="NAVFOOTER"
|
|
><HR
|
|
ALIGN="LEFT"
|
|
WIDTH="100%"><TABLE
|
|
SUMMARY="Footer navigation table"
|
|
WIDTH="100%"
|
|
BORDER="0"
|
|
CELLPADDING="0"
|
|
CELLSPACING="0"
|
|
><TR
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="left"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="random-numbers.html"
|
|
ACCESSKEY="P"
|
|
>Prev</A
|
|
></TD
|
|
><TD
|
|
WIDTH="34%"
|
|
ALIGN="center"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="index.html"
|
|
ACCESSKEY="H"
|
|
>Home</A
|
|
></TD
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="right"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="crypto.html"
|
|
ACCESSKEY="N"
|
|
>Next</A
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="left"
|
|
VALIGN="top"
|
|
>Random Numbers</TD
|
|
><TD
|
|
WIDTH="34%"
|
|
ALIGN="center"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="special.html"
|
|
ACCESSKEY="U"
|
|
>Up</A
|
|
></TD
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="right"
|
|
VALIGN="top"
|
|
>Cryptographic Algorithms and Protocols</TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></BODY
|
|
></HTML
|
|
> |