When clever security ends up as no security.............an Apex warning



This week one of the guys in my team (Vivek) told me he'd noticed some worrying behaviour with our Apex applications since we moved to ldap authentication. He was saying that he could authenticate with no password at all.....

Initially i thought it must be some sort of weird caching thing letting him log in but after a short investigation with him it seems there is a massive flaw with apex ldap authentication - and it's pretty fundamental.......

If you put your username in as normal but leave the password as null, click login and you get straight in!

This is a massive hole - perhaps the worst part of it being that you can easily log in as somebody else by just using their username and a null password.

This must be a bug surely?

After looking on google i've seen a couple of people discussing it - most notably on Patrick's blog - however this was a few years ago and i thought something may have changed - but it hasn't.

Some of the description revolves around the fact that the ldap server allows anonymous binds and this is somehow the cause of it - in our case however our AD server definitely does not allow anonymous binds - see output here






However if we use the following code block (with serverout on from sqlplus)  authentication would be passed (server names etc changed for comedy effect)


DECLARE
  l_retval      PLS_INTEGER;
  l_retval2     PLS_INTEGER;
  l_session     dbms_ldap.session;
  l_ldap_host   VARCHAR2(256);
  l_ldap_port   VARCHAR2(256);
  l_ldap_user   VARCHAR2(256);
  l_ldap_passwd VARCHAR2(256);
  l_ldap_base   VARCHAR2(256);
BEGIN
  l_retval                := -1;
  dbms_ldap.use_exception := TRUE;
  l_ldap_host             := 'oracle.com';
  l_ldap_port             := '389';
 l_ldap_user             := 'ORACLE\LARRY';
  l_ldap_passwd           := '';
  l_session               := dbms_ldap.init(l_ldap_host, l_ldap_port);
  l_retval                := dbms_ldap.simple_bind_s(l_session,
                                                     l_ldap_user,
                                                     l_ldap_passwd);
  dbms_output.put_line('Return value: ' || l_retval);
  l_retval2 := dbms_ldap.unbind_s(l_session);
EXCEPTION
  WHEN OTHERS THEN
    dbms_output.put_line(rpad('ldap session ', 25, ' ') || ': ' ||
                         rawtohex(substr(l_session, 1, 8)) ||
                         '(returned from init)');
    dbms_output.put_line('error: ' || SQLERRM || ' ' || SQLCODE);
    dbms_output.put_line('user: ' || l_ldap_user);
    dbms_output.put_line('host: ' || l_ldap_host);
    dbms_output.put_line('port: ' || l_ldap_port);
    l_retval := dbms_ldap.unbind_s(l_session);
END;
/


Return value: 0

PL/SQL procedure successfully completed.


So in the case above if this was an internal application at Oracle I could login directly as Larry himself.........


So the behaviour seems to be when running from apex (or indeed using the DBMS_LDAP package) :

1) valid username + valid password = login as valid username
2) valid username + valid password = login fail
3) any username + null password = login as any user
4) null username + null password = login as null

Scenario 3 + 4 are pretty shocking......

It seems that the return code from the function when nulls are passed is  "Authentication Passed!"

Now the fix seems to be to make sure that the username/password are never null in some sort of validation routine somewhere before the ldap authentication is called - easily done of course so the hole is simple to close.

I wonder though how many shops have missed this flaw during testing and the system is essentially wide open. I suggest anyone using ldap to authenticate needs to check this ASAP!



4 comments:

  1. Oracle should consider adding not null validation to the password field on the login page in Apex by default. Those that wish to accept a null password can delete the validation.

    ReplyDelete
  2. Good God !! Thanks for posting this Richard..

    ReplyDelete
  3. APEX 5.0 : "Password must have some value."

    ReplyDelete
    Replies
    1. Thats cryptic - are you saying Apex 5 forces some value by default here?

      Delete