Bug 4550 - RFE: Add secure user authentication to spamc/spamd protocol
Summary: RFE: Add secure user authentication to spamc/spamd protocol
Status: RESOLVED WORKSFORME
Alias: None
Product: Spamassassin
Classification: Unclassified
Component: spamc/spamd (show other bugs)
Version: SVN Trunk (Latest Devel Version)
Hardware: Other other
: P5 enhancement
Target Milestone: Future
Assignee: SpamAssassin Developer Mailing List
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 4560
  Show dependency tree
 
Reported: 2005-08-21 15:32 UTC by Sidney Markowitz
Modified: 2022-03-06 16:25 UTC (History)
2 users (show)



Attachment Type Modified Status Actions Submitter/CLA Status
Proof of Concept Patch patch None Michael Parker [HasCLA]

Note You need to log in before you can comment on or make changes to this bug.
Description Sidney Markowitz 2005-08-21 15:32:21 UTC
Bug 4546 brought up the issue that spamc -L in the absence of authentication of
the user name opens vulnerabilities. In anticipation of that bug being closed by
making spamd learning disabled by default, to be enabled only in a suitably
secure environment, I'm opening this RFE to discuss how to do spamc -L securely
in less restrictive environments.

My first proposed solution is described in bug 4546 comment 7 but I would be
happy to see ideas that are easier to implement and more lightweight to run.
Comment 1 Michael Parker 2005-08-21 17:16:49 UTC
Subject: Re:  [RFE] Add secure user authentication to spamc/spamd
 protocol

a) it should be a plugin, adding appropriate hooks to spamd to do the
authentication

b) I'll veto any patch that does not include performance numbers.

Michael
Comment 2 Sidney Markowitz 2005-08-21 18:01:08 UTC
What's involved in making something a plugin for spamd, as opposed to a
SpamAssassin plugin? Do we have any spamd plugins already?

If we go with something very lightweight, such as adding a password
configuration option in user_prefs and spamc.conf and adding the password field
to the protocol, then I don't see how or why it would be done as a plugin. I
agree that if we do anything more, such as have a cryptographic secure
handshaking authentication protocol, that would be best in a plugin.
Comment 3 Michael Parker 2005-08-21 18:11:17 UTC
Subject: Re:  [RFE] Add secure user authentication to spamc/spamd
 protocol


>------- Additional Comments From sidney@sidney.com  2005-08-21 18:01 -------
>What's involved in making something a plugin for spamd, as opposed to a
>SpamAssassin plugin? Do we have any spamd plugins already?
>  
>
There are a couple of spamd plugin hooks now, no published plugins that
make use of the hooks, but they are being used.  Nothing extra involved
to put the hook in spamd.

>If we go with something very lightweight, such as adding a password
>configuration option in user_prefs and spamc.conf and adding the password field
>to the protocol, then I don't see how or why it would be done as a plugin. I
>agree that if we do anything more, such as have a cryptographic secure
>handshaking authentication protocol, that would be best in a plugin.
>  
>

It should be very easy for admins to create a plugin that will obtain
the authentication information from their own, possibly custom,
database.  Then you just create the hooks and a basic plugin (this
plugin can do perform the basic user_prefs config option password deal)
and leave it up to the administrator to supply anything more
complicated.  That is the entire reason for plugins.

FYI, there is actually a plugin hook that might be useful here,
services_authorized_for_username.  See the call in one of the BayesSQL
modules for an example of how it is used.  And, now that I think about
it, given some spamd protocol header parsing foo and this plugin hook it
would be trivial to add the basic, send a password in the header and
check it against a value in a user_prefs file, solution.

Michael
Comment 4 Duncan Findlay 2005-08-21 18:20:47 UTC
Subject: Re:  [RFE] Add secure user authentication to spamc/spamd protocol

Though the tough part, as always is fixing spamc to pass whatever it
needs to pass.

I'm thinking if we starting going down the spamd plugin road too far
we're going to need to start having some sort of a "capabilities"
command so that spamd/spamc can see what "extensions" (i.e. plugins)
are supported.
Comment 5 Michael Parker 2005-08-21 18:26:05 UTC
Ok, some more details on a possible solution.

1) In spamd.raw parse_headers you add a spamd_parse_headers plugin hook. 
Initially I was thinking as just an else case but I can see value in letting
plugins step in for any of the headers.

2) Then you add the services_authorized_for_username plugin hook in sub check
and sub dotell passing in the appropriate service (ie check, report, process,
learn, etc).

3) Then you add a new command line option to spamc that accepts a password and
adds a password (or something else) header to the spamd protocol stream.

4) Then you create a plugin that has a hook that reads in the new password
header and resonds to the services_authorized_for_username call with the
appropriate response.  It would also allow a new config option, choose whatever
name you want really, that allows the user to specify the password.  The plugin
would then compare the passed in password with the one in the config and use
that to generate it's response.

Bonus points for doing interesting things with the password, like MD5 hashes or
other obfuscation techniques.


I know it's basic, but in the long run I see plugins that instead of looking in
the user config it will do some database or ldap lookups to determine if the
user is authorized.
Comment 6 Sidney Markowitz 2005-08-21 19:06:27 UTC
The spamc password should be in the spamc config file, not on the command line
(although a command line option that says to require a password is ok) so that
the password does not show up in ps and command history lists.

We should make it unlikely that someone will unthinkingly use password
authentication where it can be sniffed. Perhaps we can enable it only when using
a command line option --vpn that does nothing but indicate that the sysadmin
claims that spamc/spamd communitcation is being done over a secure network,
e.g., SSL or a VPN or on localhost.

It would be a huge change to the protocol to make it session oriented. Without
sessions and handshaking, the only way I see to avoid sending the password in
the clear involves hashing the entire message... Oh, wait, don't spamc and spamd
already read the entire message into memory? That means that they can hash it,
which means that spamc can include a hash combining the message, the protocol
command, the user name, the time, and the password. Spamd would use its copy of
the password to verify the hash, which verifies the password as well as the
integrity of the message transmission, with the password never being sent in the
clear.

I just has another idea... The password could be used by spamc to encrypt the
message (actually password used to encrypt a session key used to encrypt the
message). Spamd verifies the password by successfully decrypting, and sends back
the result encrypted with the same session key. Not only do we get
authentication without handshaking, but we get message confidentiality without
the overhead of SSL. If we do that, it definitely has to be done as a plugin.
Comment 7 John Gardiner Myers 2005-08-22 09:57:49 UTC
(In reply to comment #4)
> I'm thinking if we starting going down the spamd plugin road too far
> we're going to need to start having some sort of a "capabilities"
> command so that spamd/spamc can see what "extensions" (i.e. plugins)
> are supported.

See attachment 3054 [details] of bug 4517.
Comment 8 Sidney Markowitz 2005-08-22 11:56:01 UTC
Query for capabilities may not be all that important because spamc and spamd
configurations have to match anyway. You would not use spamc as the client to an
arbitrary spamd server. For example, if I set up a spamd server that uses the
foo plugin for authentication, all my users have to have spamc configured to use
the foo plugin. One step in the instructions to them on setting up the use of
SpamAssassin is that they enable foo plugin in spamc. There will be no reason
for spamc to query spamd for foo capabilities and no reasonable fallback
behavior if spamd reports not having foo.
Comment 9 Justin Mason 2005-08-22 12:17:24 UTC
First off, using plugins to extend spamd is definitely worth doing.  I've been
planning to do it for a long time.   I'm planning to move out all the odd little
authentication systems (vpopmail, etc.) into plugins, instead of having that
code littering around spamd.raw -- which is messy and buggy.

Secondly, re capabilities.  When thinking about spamc and spamd, the best
parallel is to think in terms of the HTTP protocol, not SMTP or POP.  so
capabilities, and capability advertising, is not likely to be useful, in my
opinion -- there's no "banner" sent from server to client, before the client
issues its request, so how's the client going to know what the server supports?
Instead of thinking in these terms, look at how the HTTP/HTTPS protocol solves
these problems.

As a result, in my opinion we should have:

  - no authentication on the userid passed (as in current trunk), if spamd has
    the command line flag to allow that.
  - simple password auth, modeled on HTTP basic authentication.  Warn, as with
    HTTP basic auth, that the pwd is sniffable.
  - simple password auth as above, over an SSL channel.

Some notes:

  - The last one is a secure way to do it.  Note that there is *no* additional
    secure method -- because it's easier just to use SSL and let *that* do the
    hard work of keeping the pwd secret, instead of inventing our own secure
    protocol!  Believe me, I've been down that road before.
  - If connection open/close handshaking is an issue, then we add a
    connection-persistence hook to the protocol, similar to HTTP Keepalive in
    HTTP/1.0 vs HTTP/1.1.   we could also do the "session key" idea, but I
    think keepalive is more useful.
  - If we have >1 methods of userid auth for learning, we will need some way
    for spamd sysadmins to indicate their site policy (e.g. "all users must use
    auth over SSL").
    


PS: Michael, +1 in general on the comment 5 idea.

>add a spamd_parse_headers plugin hook. Initially I was thinking as just an
>else case but I can see value in letting plugins step in for any of the
>headers.
  
+1 for either; I can see the usefulness of the latter, as long as the plugin
doesn't interfere with other plugins (or the core) seeing the header.



PPS: spamc password UI -- why not emulate rsync?  support passing it in through
an environment var, it works well for rsync, should work here too.



PPPS: I don't see how att 3054 on bug 4517 is relevant -- the have_plugin()
call?  not getting it.


Comment 10 Sidney Markowitz 2005-08-22 15:59:57 UTC
I mostly agree with Justin's comment 9, with these further comments:

No auth is fine. --auth-ident is useful with it. Do we want to implement it as a
plugin, though?

In HTTP basic authentication, the client sends a name/password in the clear in
two fields in the protocol. The server can send a request for authentication to
the client and the client then has to respond with it. In our case there is no
need for spamd to send a request for authentication to spamc. HTTP encodes the
password in BASE64, which seems like a good idea for our protocol. So what we
are left with that we add another field to the record that spamc sends in
addition to the existing user name field, which will contain 'pwd:' and the
BASE64 encoded password.

That basic authentication becomes secure when used with SSL or with a VPN or SSH
tunnel.

I agree that it would be a headache to design our own secure protocol. However,
we should make sure that the plugin API makes it possible for someone to use a
plugin that encrypts/decrypts the message using a per-user key that spamc and
spamd have access to. That provides security that is a lot more lightweight than
establishing an SSL session each time or requiring every user to have a VPN
tunnel to the server. I might write such a plugin.

I don't see any reason for persistent connections. Let's not add a keepalive
header unless a reason for it comes up. If one does, I agree with the HTTP 1.0
style of header that has no keepalive by default and a 'connection: keepalive'
field to keep the connection open.
Comment 11 Michael Parker 2005-08-23 23:48:43 UTC
Created attachment 3098 [details]
Proof of Concept Patch

Here is a proof of concept patch to illustrate my idea.  It's far from complete
but I think you can get the general idea.  We add a plugin hook for
spamd_parse_headers to pick up any un-handled headers (ie our Password: foo
header that we want to add) and we insert the services_authorized_for_username
hook at the top of dotell, and eventually maybe check if we wanted and then act
accordingly for the return value.  The plugin checks the password against an
htpasswd file that we setup on the server.

Like I said, strictly a proof of concept that I whipped up in about an hour, it
needs some work but shows the diirection I think we should head.
Comment 12 Sidney Markowitz 2005-08-29 11:38:43 UTC
There's a relatively new feature that has been added to the TLS standard by the
IETF and that is implemented in OpenSSL called TLS-PSK. I want to mention it
here so the idea doesn't get lost. It may be a good way to do this. Here is a
brief comment about it quoted from a cryptography expert who was talking about
it on a mailing list I subscribe to. Google to get full context from the mailing
list archive if you are curious.

Peter Gutmann wrote:

> TLS-PSK fixes this problem by providing mutual authentication of client and
> server as part of the key exchange.  Both sides demonstrate proof-of-
> possession of the password (without actually communicating the password), if
> either side fails to do this then the TLS handshake fails.

If we use TLS-PSK for the SSL spamc/spamd connection, we get the secure
authentication all taken care of with a standards-based protocol. I do need to
read more about it to find out if it is indeed practical to use it with a
separate password for each user in many-users environment. I don't yet know how
OpenSSL deals with storing the various client passwords on the server.
Comment 13 Justin Mason 2006-05-26 10:17:54 UTC
Title: Secure user authentication in the spamd protocol

This was a suggested idea for the Google Summer of Code 2006;
I'm adding it to the bugzilla for future use, and in case anyone feels
like implementing it.

Subject ID: spamassassin-secure-user-auth
Keywords: spamd, protocol, tls, perl
Description: http://issues.apache.org/SpamAssassin/show_bug.cgi?id=4550 : a
secure method to authenticate users over a spamc/spamd connection.
Possible Mentors: Justin Mason (jm at jmason.org)
Comment 14 Justin Mason 2006-12-11 04:05:29 UTC
I don't think this is likely to make 3.2.0
Comment 15 Mark Martinec 2009-11-11 11:40:31 UTC
> I don't think this is likely to make 3.2.0

Apparently it's not going to happen for 3.3.0,
changing target to 'future'.
Comment 16 Henrik Krohns 2022-03-06 16:25:07 UTC
Closing ancient stale bug.