Re: Securing data to a process principal
- From: lelteto <lelteto@xxxxxxxxxxxxxxxxxxxxxxxxx>
- Date: Wed, 5 Mar 2008 11:36:01 -0800
You are mistaken on one important point: local admins will ALWAYS be able to
retrieve your secrets, monitor your code, etc. Yes, you can protect against
them "somewhat" (ie. casual browsing would not show them the keys), but it is
always possible to write a debugging code (or simply a monitoring tool which
hooks into your encryption function) and you cannot prevent an admin using
that.
So IF you accept that you cannot protect against admins (at least not in
software) do you still need stronger protection than ACLs?
Laszlo Elteto
SafeNet, Inc.
"Steve Schuler" wrote:
Hi again Laslo -.
Yes, the accounts would be domain accounts. However, they are not "user"
accounts but are service accounts, so nobody ever does an interactive logon
using these accounts.
On your suggestions, the problem with #1 is that the password is not always
the same. There are 100s of these service accounts and my utility will not
"own" them. On #2, a variation of this (using ACLing) is what I'm doing
today to lock down the keys. The problem with ACling is that it does not
protect secrets from local admins of the box, and it does not protect a
secret it "gets loose" from its ACLed container. What I'm after is something
better.
Let me explain a little more about the use cases for this - we have a
current utility and workflow it facilitates, and I am seeking to upgrade the
utility with a stonger protection model.
Use cases & workflow:
1) Risk Management analyst creates domain service ID & password (an account
not in Domain Users default group, but in a ServiceIDs group in the domain).
The RM analyst also uses an app that has an embedded obfuscated key (I'll
call it the "master" key) to encrypt the ID/PW and put it into a strongly
ACLed SQL DB (the "service ID DB"). In addition to the service ID and PW,
the RM analyst specifies the "component type" (e.g., IIS worker process,
service, ODBC connection object) the ID / PW can be configured to, and a
group of servers or "component level" (e.g., "development", "acceptance
testing", "production") that the service ID / PW can be applied to. Some
component types - e.g., ODBC connection strings - also take the name of a
second domain ID or group (I'll call this the "app ID") that is allowed to
access the component type (I'll explain this further in #2 & #3).
2) A resource owner (e.g., an IIS admin) who is a local admin of some
resource is ACLed to be able to call a second app service (which also has
the master key) that can read from the service ID DB. This second app
"knows" how to drive the configuration APIs of all "component types" and it
checks that the specified component type in the service ID DB matches the
type the resource owner is asking it to configure. In the case of components
that take an ID and password at configure time such as an IIS application
pool or service Run As, that is done immediately. In the case of a component
type like an ODBC connection object, where the password is used at run time
by an application, the "package" service ID, PW, component type and level
remains encrypted, and is copied into the registry of target servers. It is
also ACLed to the app ID that is allowed to access it.
3) At run time, for resources like ODBC connection object where the PW is
not pre-configured, an app running as the ACLed app ID can call a utility
DLL that has the master key embedded in it, and pass in a connection object.
The utilty DLL decrypts the package, checks that the requested use matches
the component type and either server name or test level (we have naming
conventions for our servers), and then applies the service ID / PW to the
component (in this case a connection object), and then passes it back to the
caller.
While this may seem elaborate, note that it accomplishes two things: 1)
separation of duties (only Risk Management knows the passwords, but they
don't have to know how to configure the apps, resource owners can confgure
apps without knowing passwords, developers can write code that doesn't embed
passwords), and 2) it can protect apps from each other on the same box
because of the ACLing that is done for resources like ODBC connection
objects, where the secret is stored in the registry.
I'm trying to create a better approach to the ACLing step. The basic idea is
that in step #1 above, if provisioning a service ID for step #3, the
encryption would be done with a key that was associated with the app ID. In
particular, the app ID is itself a service ID in the service ID DB, so if I
can use a login context of the app ID itself as the encryption key as I've
outlined below, then instead of using an embedded master key, I can have the
RM analyst app in step #1 do a LogonUser with the app ID, and then use the
approach outlined below to use the thread's impersonation context to encrypt
the service ID. Then in step #3, the running security context of the app ID
can do the decrypt, without requiring that the utility DLL have an embedded
master ID. So not only would this be an improvement over ACLing because the
service ID / PW can't "get loose", but it removes another problem - the need
to embed a master key in the utility.
Again, thanks for any comments.
Thanks,
Steve Schuler
Safeco Insurance
"lelteto" <lelteto@xxxxxxxxxxxxxxxxxxxxxxxxx> wrote in message
news:DEF1759A-02E7-4DB5-BD51-B690CC860E99@xxxxxxxxxxxxxxxx
Steve,
You say that you want to lock to a "principal" - but then you say the same
application should be able to decrypt data on another computer. So are you
talking about a DOMAIN user? If not, how do you know if the user has the
same
password on multiple computers?
In case of domain, you may use domain objects (just create a random
encryption key first time for the user - and use it later). That would be
the
simplest.
If you need to support independent computers obviously you need some
SHARED
secret (key). There are two ways you could do it:
(1) if you assume that the password is always the same, you can derive the
key from it (you already know this part) - but then you need the
principal's
password - which should be available when you start the process AS the
principal. One possible way to do this is to have YOUR dll loaded into the
process's address space (the one which handle the
EncryptAsProcessPrincipal
function - and INJECT the derived key into the dll's data area. (Again,
load
as debug suspended - then you have control over the child process' address
space and can inject data into it.)
(2) IF you can "pre-set" the computers for each principal (user) then you
can use CAPI: you would need to use CAPI containers. Those are by default
protected TO the principal.
Laszlo Elteto
SafeNet, Inc.
"Steve Schuler" wrote:
Hello Dave and Laslo - thanks for your replies
I should probably be more careful in choice of wording. Instead of saying
"Process Identity" (which many will read as PID), I'm now going to say
"Process Principal" to make clear that the granularity I'm after is that
any
process or thread running with a security context representing the same
Windows domain Principal can decrypt a secret that was encrypted by a
process or thread running as that same Principal.
To restate my goal, I want something that helps isolate an application's
secrets from other applications on the same shared box. CryptProtectData
with machine context doesn't do that. And CryptProtectData at user
context
doesn't work because there's not necessarily an interactive user - it's
my
understanding that CryptProtectData actually requires a loaded user
profile,
but I'm talking about a non-interactive app doing the decryption - e.g.,
a
service or an IIS app host. (Is all that's really needed a loaded
profile?
If so, could I "manually" load a registry hive and profile to make it
work?
I recall seeing code that did that before.) Also, I need the decryption
to
work on multiple machines, which are going to be different than the
machine
that did the encryption. Would CryptProtectData work in any form in that
case - the docs seem to say no.
To Laslo - I don't need the encryption / decryption to be transparent and
callers will be calling explicit EncryptAsProcessPrincipal or
DecryptAsProcessPrincipal, so I don't need to go down the file driver
path.
In any case, I don't think a file driver would address my main
requirement,
which is locking things to the calling Principal.
The reason Laslo's #1 is difficult though, even though I have freedom to
specify how apps will call this code, is that I don't want to embed the
pOptionalEntropy (or more broadly, "secret") in the apps. That would just
push the problem one link up the chain - I would now have the issue of
securing pOptionalEntropy. (And yes, obfuscation of a key is the
"solution"
that's currently in use in a similar utility.) Instead, my idea is based
on
this question: is there already some secret "owned" by the running thread
that has the right granularity? And which the thread can get at? The
first
answer is yes: the NT password hash. But the answer to the second
question
is seemingly, "not easily". (And yes, the caveat that only Logon Types 2,
4
and 5 will work is OK - my targets for this are IIS app processes,
services,
and interactive apps. And I'll deal with the issue of an impersonating
thread running under a network logon by RevertToSelf-ing and then
restoring
the impersonation token.)
My idea is basically to use the password hash indirectly, via an NTLM
SSPI
operation. It seems like it should work, but I've already spotted one
problem. Namely that I'm not in complete control of whether NTLM or
NTLMv2
is done by the NTLM SSP. The introduction of the nonce and timestamp in
NTLMv2 mean that it won't work for what I want (v2 would not generate the
same challenge-response the next time it was called), and it appears that
there's no way to force SSPI to do NTLMv1 if the LMCompatibilityLevel is
set
to 3 (and here, if someone knows a way to force this, please chime in).
If anyone can see a better way to accomplish the granularity I need, I'd
appreciate the advice.
Thanks,
Steve Schuler
Safeco Insurance
"lelteto" <lelteto@xxxxxxxxxxxxxxxxxxxxxxxxx> wrote in message
news:8F5884BE-504B-4FCA-86C8-906C39CEBF37@xxxxxxxxxxxxxxxx
CryptProtectData is good for the actual encryption - but Steve's issue
is
how
to get the PER PROCESS SECRET (pOptionalEntropy).
Steve,
1. It is not clear from your description what type of data protection
(encryption) you want. If the APPLICATION is calling your code (eg.
your
DLL)
than it's relatively simple - but I guess that you want TRANSPARENT
encryption for any (arbitrary) process without modifying that
application's
code. This is actually very hard: you would need to write a File System
Filter Driver. Don't even think about starting from scratch - would be
a
multi-year project in itself (and probably still misses a lot). I would
strongly recommend contacting OSR and buying their toolkit.
(http://www.osr.com/toolkits_fddk.shtml) It's not cheap, but would
actually
allow you to do what you want.
One note: You MAY think that instead of a filter driver you can simply
hook
into the file I/O APIs (kernel32, ntdll). That would work for many
applications - and I wrote such hook in the past (part of SSI's /
Rainbow's /
SafeNet's Shell "automatic data protection" feature; also wrote a Win9x
file
system filter driver for the same). However, this doesn't work for
programs
using memory mapped files - and there are lots of such apps. The only
way
I
know to work transparently with ALL applications is using File System
Filter
Driver.
2. Seems you already have a process which KNOWS the processes you
start.
So
here is what you would need to do: set up a communication between your
starting program and your filter driver. Whenever you start an
application
you
- generate some encryption key from the password
- start it with suspended mode => get process id
- pass the {process_id, key} pair to your filter driver
- maybe you also want to pass path / filename information what to
encrypt
(or what NOT to encrypt like executables, dlls, parameter files -
whatever)
From this point your filter driver can monitor each and every file I/O
of
each process your start program REGISTERED - and ignore any other
process.
It's not trivial, but certainly doable.
Laszlo Elteto
SafeNet, Inc.
"DaveMo" wrote:
On Mar 3, 8:42 am, "Steve Schuler" <sjs...@xxxxxxxxxx> wrote:
x-posted to microsoft.public.security and
microsoft.public.security.crypto
Hello all -
I've been looking for a way to do this, and I'm hoping someone
either
can
point me at the obvious API that does this that I somehow missed
after
searching long and hard, or else can comment on an idea I'll outline
below
that I think would get me there.
First, here's what I'm trying to do: I want something similar to
DPAPI,
but
with process identity granularity. I'm going to have an
administrative
UI
that would take a service ID and password, call LogonUser, and then
call my
encryption API to encrypt data based on something unique to the
security
context created by LogonUser. Later, I want a process configured to
run
as
that service ID / password identity - and *only* processes running
with
that
identity - to be able to call a decryption API on that data. (As for
- Follow-Ups:
- Re: Securing data to a process principal
- From: Steve Schuler
- Re: Securing data to a process principal
- References:
- Securing data to a process identity
- From: Steve Schuler
- Re: Securing data to a process identity
- From: DaveMo
- Re: Securing data to a process identity
- From: lelteto
- Re: Securing data to a process principal
- From: Steve Schuler
- Re: Securing data to a process principal
- From: lelteto
- Re: Securing data to a process principal
- From: Steve Schuler
- Securing data to a process identity
- Prev by Date: Re: Securing data to a process principal
- Next by Date: Re: Securing data to a process principal
- Previous by thread: Re: Securing data to a process principal
- Next by thread: Re: Securing data to a process principal
- Index(es):
Relevant Pages
|