Warning: DBMS_LDAP.simple_bind_s/ APEX_LDAP.authenticate and NULL password

Just came across a very strange behavior of the DBMS_LDAP.simple_bind_s and APEX_LDAP.authenticate procedure which I used to do a basic LDAP authentication against our MS Active Directory server.

I used the following simple test code

DECLARE
    vSession DBMS_LDAP.session;
    vResult  PLS_INTEGER;
BEGIN
    DBMS_LDAP.use_exception := TRUE;
    vSession := DBMS_LDAP.init
                  ( hostname => 'your-active-directory-server'
                  , portnum  => 389
                  );
    vResult  := DBMS_LDAP.simple_bind_s
                  ( ld     => vSession
                  , dn     => 'CN=Wolf Patrick,[...rest of the DN...],DC=sphinx,DC=co,DC=at'
                  , passwd => 'x'
                  );
    DBMS_Output.put_line('User authenticated!');
    vResult  := DBMS_LDAP.unbind_s(vSession);
END;

which raised the expected error

ORA-31202: DBMS_LDAP: LDAP client/server error: Invalid credentials. 80090308:
LdapErr: DSID-0C090334, comment: AcceptSecurityContext error, data 52e, vece

because of the wrong password. But as soon as I set NULL for the passwd parameter I got the “User authenticated!” message!!!

Couldn’t believe that, so I also tried the APEX_LDAP wrapper package. Shows the same behavior with the following code!

BEGIN
    IF APEX_LDAP.authenticate
         ( p_username    => 'Wolf Patrick'
         , p_password    => NULL
         , p_search_base => '[...rest of the DN...],DC=sphinx,DC=co,DC=at'
         , p_host        => 'your-active-directory-server'
         , p_port        => 389
         )
    THEN
        DBMS_Output.put_line('ok');
    ELSE
        DBMS_Output.put_line('not ok');
    END IF;
END;

So I did a final test with the built-in LDAP authentication scheme of Oracle APEX. The good news is that it captures this case and you are not able to login. So it looks like they are doing an extra check for a NULL password there.

But what does that mean?!?

  1. I’m a total moron and did something completely wrong. In that case please let me know!
  2. Our MS Active Directory server is set up wrong to accept NULL passwords for LDAP connections.
  3. MS Active Directory is a total piece of crap to accept NULL passwords. (BTW, I don’t know if other LDAP servers like Oracle OID show the same behavior)
  4. All applications which are using APEX_LDAP.authenticate or DBMS_LDAP.simple_bind_s in a custom authentication scheme have a huge security flaw in them.

Can someone test the above code against his MS Active Directory or some other LDAP server and let me know?

BTW, in my opinion APEX_LDAP.authenticate should behave the same as the built-in LDAP authentication scheme and return FALSE.

Update as of 13-Jan-2008: John Scott pointed into the right direction. DBMS_LDAP.simple_bind_s has to accept a NULL password, because this function is also used to authenticate against a LDAP server if you want to do an anonymous search in the LDAP directory. I think it wasn’t the best decision by the authors of the RFC 4513 to reuse the password parameter to decide if it’s an anonymous bind or not. An extra parameter would have been much better an clearer. Anyway, we have to deal with that problem now.

If you directly use DBMS_LDAP.simple_bind_s for authentication in your code, don’t forget to do a password IS NOT NULL check. If you use APEX_LDAP.authenticate you have to do the same.

But I have good news! APEX_LDAP.authenticate will be fixed in Oracle APEX 3.1 to include this check. Thanks to the APEX team!

12 thoughts on “Warning: DBMS_LDAP.simple_bind_s/ APEX_LDAP.authenticate and NULL password

  1. Patrick,

    Your LDAP server is configured to allow anonymous binds, this is quite common and allows the LDAP information to be queried by external systems without requiring a a specific username and password to authenticate.

    Your LDAP administrator should be able to change this behaviour or tie down specific DN’s if you don’t like the behaviour.

    It’s not quite the security flaw it might appear at first if you’re not familiar with anonymous binds.

    Hope this helps

    John

  2. Yeah, I also thought about the anonymous bind thing after putting some more thoughts into that topic. I think I read it some while ago.

    But as you say, it seems to be a quite common setting of an LDAP server. All the examples you find on the internet how to do a LDAP authentication with DBMS_LDAP.simple_bind_s do not take care about that. So it’s a potential security flaw in an application.

    About the APEX_LDAP.authenticate, there I think it’s for sure a security bug, because you would not expected that a function which purpose is to authenticate has a “back door”.

    So I think it’s still good to raise that issue so that people are aware of it when they are using the above packages for authentication.

    Thanks for the input John!
    Patrick

  3. It’s not really a flaw/backdoor in APEX_LDAP, remember it is your LDAP server that is the one that is saying it is ok to bind anonymously.

    As I say your LDAP administrator can change this behaviour (I wouldn’t really want the APEX_LDAP package to try and second-guess what the anonymous binding policy was).

    John

  4. Maybe I have to be more precise, I’m not talking about adding a password IS NOT NULL check for all the APEX_LDAP procedures/functions, just for the APEX_LDAP.authenticate.

    For the other functions like APEX_LDAP.is_member it’s ok to pass NULL in case you have anonymous bind enabled on your LDAP server.

    But the APEX_LDAP.authenticate is security relevant and only used for authentication, that’s its purpose. Why should I want to allow anonymous authentication there? The built-in LDAP authentication scheme does the check, and I think by purpose.

    Patrick

  5. My issue with the behavior demonstrated here is that he didn’t do an anonymous authentication. He gave a DN (at least in the first case, using DBMS_LDAP). However, when that didn’t work, it did a fall back to anonymous. That’s really where the flaw is IMHO. You shouldn’t have to disable anonymous binding in order to return a proper code. It should fail to authenticate either way. If you want an anonymous bind, then don’t pass a DN. If you pass a DN, you obviously are trying not to be anonymous!

  6. Depends how you look at it really, APEX_LDAP.AUTHENTICATE is deferring the credentials checking to the LDAP server. Your LDAP server is supporting anonymous binds, therefore passing a null across is handled as an anonymous bind, ergo authentication succeeds.

    Turning off anonymous binds would cause the ‘correct’ behavior that you want from the APEX_LDAP.authenticate routine.

    John.

  7. Dan,

    Buried away in the LDAP server specifications somewhere I believe that it is ‘correct’ to allow an anonymous bind even if a username (i.e DN in this case) is passed in.

    In other words, if you pass in a full DN and leave the password as NULL, then an LDAP directory server which supports anonymous binds will consider this a request to perform an anonymous bind (by virtue of the password being NULL), the fact that a DN has been passed in doesn’t really come into it.

    Again, I don’t really see this as a flaw in APEX_LDAP since it is sort of conforming to the way an LDAP server supports anonymous binds.

    I see the ‘quick solution’ if you don’t want to allow NULL passwords to treated as an anonymous binds is to disable anonymous binds.

    John

  8. John,

    do you think that the average APEX developer will know about that behavior if he just wants to do simple LDAP integration in an custom authorization scheme?

    I doubt not.

    Would be interesting to know how many production applications are out there where this problem exists… Hopefully they all have a good QA department which captured that!

    Patrick

  9. Patrick,

    >do you think that the average APEX developer will
    >know about that behavior if he just wants to do
    >simple LDAP integration in an custom authorization
    >scheme?

    No, I don’t expect the average APEX developer to know about that…

    However….I most certainly expect the LDAP Administrator to know about the impact of allowing anonymous binds.

    In a case where the APEX Developer *was* the same person as the LDAP Administrator, then yes…they should know about anonymous binds.

    That was my point, when you use LDAP Authentication in APEX you are effectively saying “I wish to defer the maintenance and authentication of my users to another system/repository” and in that respect you have to assume that the person responsible for maintaining that repository (in this case the LDAP Directory) knows what they are doing.

    There is no right or wrong answer as to whether anonymous binds should be allowed or disallowed, it’s purely an internal decision that needs to be made, based on whether you have other systems that require anonymous binds to be used or not (personally I’m not a fan of anonymous binds, however they serve a purpose).

    One of the best pieces of advice I could give to anyone starting to integrate their APEX apps with their LDAP directory is to work closely with your LDAP administrator, because it will make your life much much easier (as I don’t expect the average APEX developer to already know the specific DN’s and LDAP attributes they need to use, however your LDAP administrator should be able to guide you on that).

    You’re looking purely at the APEX app perspective here, sure you could take the NULL password into account and have the authenticate routines pass back false, however don’t forget that the LDAP directory could (and likely is) be used by many *many* other systems, such as SSH servers, Windows domain login, Email account authentication and so on, all of these systems can be written in a variety of languages, C, Perl, .NET etc…….

    My point? Well…if your LDAP server allows anonymous binds then it will allow anonymous to any of these systems (unless they perform the explicit check themselves). Even if those systems do perform a special check themselves, someone could easily code up some Perl code (or whatever) to perform an anonymous bind in just a few lines of code.

    You could easily write your own wrapper around the APEX routines to add a check for NULL password, however if you really want to disallow anonymous binds the place to do it is at the LDAP server.

    John.

  10. Here’s an except from RFC 4513: “LDAP server implementations MUST support the anonymous authentication mechanism of the simple Bind method (Section 5.1.1).”

    I’m not sure a standards-conforming LDAP server can disable anonymous binds. However, this discussion is really about “Unauthenticated Authentication” binds described in section 5.1.2. This mechanism is selected by passing a non-zero length DN and a zero-length password.

    I don’t see anything indicating that a server must implement this mechanism; however, section 6.3.1 explicitly addresses the concerns raised here and says “Clients that use the results from a simple Bind operation to make authorization decisions should actively detect unauthenticated Bind requests (by verifying that the supplied password is not empty) and react appropriately.”

    When this thread was brought to my attention, I was a bit surprised too; however, it appears the protocol has some features that must be accounted for when one is using a bind against an LDAP server as a way of proving that a user is who he/she says.

    Rodney

  11. Rodney,

    “MUST support” is not the same as “MUST be enabled”, “MUST support” implies that the LDAP server must be able to handle it if it is enabled.

    Sure the client should do some detection too, if necessary, however my view is that disabling anonymous binds on the server makes much of this argument moot.

    Also, section 5.1.2 of the RFC quotes –

    “Additionally, Servers SHOULD by default fail Unauthenticated Bind requests with a resultCode of unwillingToPerform”

    Which is open to a little bit of interpretation, but suggests (to me) that the default should be that the Server fails unauthenticated binds (i.e default is ‘off’, with the option to turn it on).

    Many LDAP servers do indeed ship with anonymous binds disabled, infact Windows 2003 Domain Controllers should ship with anonymous binds disabled (of course you can then enable if you like) –

    http://support.microsoft.com/default.aspx?scid=326690

    So it sounds like Patricks AD is either an earlier version (where anonymous binds were enabled by default perhaps), or has been manually enabled for anonymous binds.

    John.

Comments are closed.