Skip to Main Content
  • Questions
  • Security -- Basic Authentication on the web over HTTP

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Bj?rn Erik.

Asked: September 25, 2000 - 2:40 am UTC

Last updated: December 11, 2011 - 4:40 pm UTC

Version: 8i

Viewed 10K+ times! This question is

You Asked

I've studied the HTTP-headers going back and forth from client/server during Basic Oracle authentication.

I register that once the user is correctly logged on, a encrypted version of username/pw is sent as a response from the client to every call to the server.

So my question is this:

1. Are there any way to protect this security risk? As I see it one HTTP-header is all that is needed to break into a users account.

2. Is there a way to remove this header, so to speak, after use? Like a log-off-button. Or maybe say: If user/PW has not been sent from a HTTP-header the last 30 minutes we prompt a new logon-screen?

And then one more question:

3. Do you recommend to use the spare-fields (spare1-spare6) in the user-tab for custom user data? Like storing the users language.


Thanks in advance.







and Tom said...


The HTTP headers and how basic authentication works are well documented features of that protocol.

To use basic authentication what happens is this:

1) you enter </code> http://site1/foo/hello.html
in the browser. This will cause a GET request to be submitted to the webserver at site1. This will request will look something like: 
----------------------------------------- 
GET /foo/hello.html  HTTP/1.0 
 
----------------------------------------- 

2) The webserver gets the request. It determines that it needs a userid and password for this document. It does not see one in the request above (just a GET so far). It will return a document such as: 
 
------------------------------------------- 
Content-Type: text/html 
Status: 401 Unauthorized 
WWW-Authenticate: Basic realm="SomeRealmName" 
 
This document is protected. You must send the proper authorization information 
to access it.  
------------------------------------------- 

3) The browser gets back that document and views the header. it sees the 401 Unauthorized and looks for the WWW-Authenticate line to get the realm. It looks in its little list of REALM=user/passwords it caches in memory (empty right now, we just started the browser). Therefore, it prompts you for the username/password for the realm "SomeRealmName". If you hit cancel right now, it just displays the document (which is "This document is protected. You must send the proper authorization information to access it. ", you've probably seen that before). If you put in a username/pass the browser (MOST browsers anyway) will save the username/password in a list that contains the 

  o realm name 
  o host name requesting the user/pass 
  o port the web server was running on on that host 

The browser then submits a request that looks something like: 
------------------------------------- 
GET /foo/hello.html HTTP/1.0 
Authorization Basic dGt5dGU6dGlnZXI

------------------------------------------------- 

4) the webserver recieves this new request, sees foo needs basic auth, sees the user/pass in the header, verifies it. If the username/password don't match, goto 2 and start over. If it does match the page /foo/hello.html is returned. Assumed it matched. 


5) I now goto 
http://site2/something/else.html

6) I now goto 
http://site1/foo/another_page.html <code>The GET request goes up, the webserver rejects with:
-------------------------------------------
Content-Type: text/html
Status: 401 Unauthorized
WWW-Authenticate: Basic realm="SomeRealmName"

This document is protected. You must send the proper authorization information
to access it.
-------------------------------------------

the browser will take the hostname/portno/someRealmName and look in its little in memory cache. this time it will find it since we just did it a couple of pages ago. It will resend the request with the username and password and we get our page.....

In short, the browser remembers your password for you. It associates a username/passowrd with a HOST, PORT, and REALM. The webserver asks the browser for this information by rejecting the request.....



The username and password are encoded in the HTTP header using a base-64 encoding scheme (a very lightweight encoding scheme, trivial to decode -- email uses this to send binary data in 7 bit ascii format).

If you use SSL (recommended with basic authentication) the entire converstation is encrypted -- including the HTTP headers. That is the answer to question #1 above.

As for number 2 above -- the answer is "no". The browser would have to implement this feature as IT is the one doing the caching of the username/password. There are simply no mechanisms for timing this out in the protocol at all. You would have to ask your browser vendor to offer this feature. There is nothing we can do at the server side to fix this.

as for #3, feel free to follow up with another question but I really don't understand the context of that question. I'm not sure what you are asking about there.

Rating

  (11 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Follow on Basic Authentication

Quinn P. Sinnott, October 04, 2002 - 8:56 am UTC

Tom,

As usual your advice is 100% worth following and I set up our 9iAS Rel 1 modpl/sql using SSL since we use basic authentication. I also set up a dedicated listener for modpl/sql and have connection pooling enabled.

Ran across a curious event that makes me wonder what is going on in terms of basic authentication and the userid/password cached by the browser as you indicated in this message. Most of the time it seems to work fine. When a user connects and I look at the Oracle processes I see that if this user is the only one then they grab 5 (ias setting) httpd sessions from the pool. As other users come in these sessions flip flop around. After 15 minutes idle the sessions die.

Enough boring background, the curious event is when a user changes their password in Oracle something weird happens and they can still log in with old password - AS LONG as at least ONE of the httpd sessions is still assigned to them? If they get bumped by other users or time out then no problem, but if they change Oracle password (verified by trying sqlplus - it is definitely changed, sqlplus notices) close the browser, go back in and at the basic authentication prompt use the OLD password or the NEW password they get in. In one browser (Netscape 7) I think any password works as long as at least one httpd session is active for that user.

This seems to indicate that the connections don't always validate by userid/password but through some other magic connect id or something like that? I don't think it's a huge problem since an active system would swap connections in the pool often but I am very curious about the mechanism in effect here?

Tom Kyte
October 04, 2002 - 6:37 pm UTC

They are caching the user/password in the middle tier for that cached connection. So, when you are rejoined with your in progress session -- it just checks to make sure the user/password used to establish the existing db connection matches what the browser sent up.

I know what Bj?rn Erik meant (last question)

MT, October 28, 2002 - 7:58 pm UTC

Tom, for Bjørn's question you wanted clarified I believe he is talking about the table: sys.user$

There are 6 fields named: spare(N)

N = 1,2,3,4,5,6

My guess is we are not supposed to touch a SYS table...but the names are misleading. What are they for?


Tom Kyte
October 28, 2002 - 8:07 pm UTC

ahh -- yes, that is probably what he meant.

you shouldn't touch the sys table. the names are meaningless outside of redwood shores CA.

A clarification

Kamal Kishore, June 06, 2003 - 8:50 pm UTC

Hi Tom,
Recently I had a discussion with one of my co-worker about how the browser handles the cached loginname/password after initially prompting the user.
He said that once you enter your loginname and password browser caches it (so far agreed), and for subsequent requests to the web server, the browser automatically sends the cached loginname/password (without the web server first rejecting it as un-authorized).
My question then is,

After the loginname/password is cached by the browser:
1). For subsequent GET requests to the same server, will the browser sent the cached loginname/password without waiting for the web server to return an un-authorized response?
OR
2). Even if the loginname/password has been cached by the browser, every time the user wants to access a page from the same web site, the browser first sends the header without the password, gets the un-authorized response and then sends the request again with the encrypted username/password? What I mean is, does the browser wait for the web server to specifically reject the request every time before sending the encryted password?

Which one of the above two actually happen?
Thanks,


Tom Kyte
June 07, 2003 - 9:11 am UTC

1) it uses the exact HOSTNAME, PORT NUMBER an REALM (so asktom.oracle.com is different then asktom.oracle.com:80 is different then asktom.oracle.com realm "foo")

it'll send the u/p

Lets say at site1, the url /foo/ is protected via basic authentication. Then......

1. you enter </code> http://site1/foo/hello.html
in the browser. This will cause a GET request to be submitted to the webserver at site1. This will request will look something like:

----------------------------------------- 
GET /foo/hello.html  HTTP/1.0 
 
----------------------------------------- 

   2. The webserver gets the request. It determines that it needs a userid and password for this document. It does not see one in the request above (just a GET so far). It will return a document such as:

 
------------------------------------------- 
Content-Type: text/html 
Status: 401 Unauthorized 
WWW-Authenticate: Basic realm="SomeRealmName" 
 
This document is protected. You must send the proper authorization information 
to access it.  
------------------------------------------- 

   3. The browser gets back that document and views the header. it sees the 401 Unauthorized and looks for the WWW-Authenticate line to get the realm. It looks in its little list of REALM=user/passwords it caches in memory (empty right now, we just started the browser). Therefore, it prompts you for the username/password for the realm "SomeRealmName". If you hit cancel right now, it just displays the document (which is "This document is protected. You must send the proper authorization information to access it. ", you've probably seen that before). If you put in a username/pass the browser (MOST browsers anyway) will save the username/password in a list that contains the
          * realm name
          * host name requesting the user/pass
          * port the web server was running on on that host 
      The browser then submits a request that looks something like:

------------------------------------- 
GET /foo/hello.html HTTP/1.0 
Username: scott:tiger 
 
------------------------------------------------- 

      (the username: part is wrong, it would be base64 encoded in the real world)

   4. the webserver recieves this new request, sees foo needs basic auth, sees the user/pass in the header, verifies it. If the username/password don't match, goto 2 and start over. If it does match the page /foo/hello.html is returned. Assumed it matched.

   5. I now goto 
http://site2/something/else.html

   6. I now goto 
http://site1/foo/another_page.html <code>The GET request goes up, the webserver rejects with:

-------------------------------------------
Content-Type: text/html
Status: 401 Unauthorized
WWW-Authenticate: Basic realm="SomeRealmName"

This document is protected. You must send the proper authorization information
to access it.
-------------------------------------------

the browser will take the hostname/portno/someRealmName and look in its little in memory cache. this time it will find it since we just did it a couple of pages ago. It will resend the request with the username and password and we get our page.....

In short, the browser remembers your password for you. It associates a username/passowrd with a HOST, PORT, and REALM. The webserver asks the browser for this information by rejecting the request.....


that is the way it is supposed to happen, so that your u/p is not sent to a routine that is not to have access to it (you can have dozens of u/p for the same site, not every page should have access to your u/p but if the browser sends it along with each request, every page would have access to it since it is just information in the header)

owa_util.get_cgi_env and Request Headers

Robert, April 30, 2004 - 12:49 pm UTC

Tom, you are the granddaddy of mod_plsql,
so I want to verify with you this:

Does owa_util.get_cgi_env actually get CUSTOM HTTP Request Headers other than that list of env variables listed in the doc ?

I am review a Web SSO product, one of the feature is the "agent sofware" plugged into Apache will add HTTP Request Headers to each browser request - session & security info.

I been under the impression that get_env_env only get those specific variables and the hard-coded "PlsqlCGIEnvironmentList" values.

Thanks


Tom Kyte
April 30, 2004 - 5:46 pm UTC

mod_plsql was branched from my owarepl code (the webdb lightweight listener code from long ago). I included ALL environment variables.

it looks like mod_plsql has kept that behaviour, everything seems to be there.

authentication

sam, July 07, 2006 - 2:34 pm UTC

Tom:

1. Can you use apache web server (without mod_plsql) to authenticate against an oracle table instead of having it use the password file in BAsic authentication?

2. Can you configure mod_plsql to protect directories and files like configuring apache to authenticate document trees.

Tom Kyte
July 08, 2006 - 10:57 am UTC

1) to authenticate "what" exactly. Sure, you can write a program that connects to Oracle and uses the supplied username/password to do so.

2) if you use mod_plsql to return the bfiles using wpg_docload (search for that package name on this site for examples), yes.

authentication

sam, July 10, 2006 - 5:04 pm UTC

Tom:

1. We have an apache web server with hundreds of files on the unix file system. This server does not have "oracle" installed. User calls the page and apache asks him for username/password and it checks the "userpasswd" text file to decide to let him in or not. Afterwards, every file the user calls for is authentiated by the same userid/password except it is passed from browser cache so user does not have to type it in in the same browser session. We are using Apache basic authentication.

I have all these users in an oracle table on another server on same network. It has 8IAS and an 8i database.

Basically I want to let apache "on machine A" validate username/password inputed by user against the oracle table on machine B instead of looking at the passwd text file on the web server. I read that apache can authenticate against MySQL database. I also heard of some module MOD_AUT_ORA but could not find anything on it.

How would you do this if it can be done?

2.WPG_DOCLOAD is a package to download/upload files from/into database. The files I have are on the unix file system (not in database).

Would I be able to open these files on the unix filesystem (binary/text) using mod_plsql? or I can only point to it on the other web server using <HREF>.

3. Would i be able to protect the files/resources in #2 using mod_plsql and turning off the apache basic authentication?New files are added every day to the filesystem.



authentication

sam, July 12, 2006 - 11:35 pm UTC

Tom:

You do not have any hint for a reference or book on the above subject on how/what to use to let apache authenticate against an oracle table? is it done using oracle libdbi drivers for MOD_AUTH_ORA8 or MOD_AUTH_DBI.

Tom Kyte
July 13, 2006 - 7:45 am UTC

not really, I don't configure apache myself and I do things entirely in the database (eg: I've not myself tried to protect files in the file system on the application server using the oracle username/password)

Re: above

Matthew, July 13, 2006 - 3:56 pm UTC

You would need to use JDBC to allow Apache to access Oracle.

Custom HTTP Headers

Jack Wells, December 11, 2011 - 2:51 pm UTC

Tom,

Following on from "Robert from ct" comment above about custom http headers... I need to write a procedure to interrogate any custom http headers sent in the request to my mod_plsql procedure. In my case, it is a "webservice consumer" calling my "webservice provider" (i.e. my PL/SQL package). I wrote a test script to see if mod_plsql respected *all* headers in the http request and it appears that it doesn't. Can you reproduce my results in your environment? Here's the code:

"hello" procedure to put in your DAD target schema:
CREATE OR REPLACE PROCEDURE hello
AS
BEGIN
  htp.htmlopen;
  htp.headopen;
  htp.title ('Hello');
  htp.headclose;
  htp.bodyopen;
  htp.header (1, 'Hello');
  htp.hr;
  owa_util.print_cgi_env;
  htp.hr;
  htp.bodyclose;
  htp.htmlclose;
END hello;
/


Test webservice "consumer" of hello procedure:
DECLARE
  lo_request_handle    utl_http.req;
  lo_response_handle   utl_http.resp;
  lv_response_line     VARCHAR2 (32767);
BEGIN
  lo_request_handle := utl_http.begin_request (
    'http://www.mysite.com:port/pls/hello',
    'GET',
    'HTTP/1.1');
  --
  -- Set a custom HTTP header for "hello" webservice
  --
  utl_http.set_header (lo_request_handle, 'X-Special', 'abc');
  lo_response_handle := utl_http.get_response (lo_request_handle);
  LOOP
    utl_http.read_line (lo_response_handle, lv_response_line, TRUE);
    dbms_output.put_line ('Body: ' || lv_response_line);
  END LOOP;
EXCEPTION
  WHEN utl_http.end_of_body THEN
    utl_http.end_response (lo_response_handle);
END;
/


My results:
Body: <html>
Body: <head>
Body: <title>Hello</title>
Body: </head>
Body: <body>
Body: <h1>Hello</h1>
Body: <hr />
Body: PLSQL_GATEWAY = WebDb<br />
Body: GATEWAY_IVERSION = 2<br />
Body: SERVER_SOFTWARE = Oracle-Application-Server-11g<br />
Body: GATEWAY_INTERFACE = CGI/1.1<br />
Body: SERVER_PORT = 80<br />
Body: SERVER_NAME = psphub.biomet3i.com<br />
Body: REQUEST_METHOD = GET<br />
Body: PATH_INFO = /hello<br />
Body: SCRIPT_NAME = /datahub<br />
Body: REMOTE_ADDR = 10.14.10.154<br />
Body: SERVER_PROTOCOL = HTTP/1.1<br />
Body: REQUEST_PROTOCOL = HTTP<br />
Body: REMOTE_USER = psp<br />
Body: HTTP_HOST = pbgpspp2.biomet.local<br />
Body: WEB_AUTHENT_PREFIX = <br />
Body: DAD_NAME = datahub<br />
Body: DOC_ACCESS_PATH = docs<br />
Body: DOCUMENT_TABLE = psp_file_uploads<br />
Body: PATH_ALIAS = rest<br />
Body: REQUEST_CHARSET = AL32UTF8<br />
Body: REQUEST_IANA_CHARSET = UTF-8<br />
Body: SCRIPT_PREFIX = <br />
Body: <hr />
Body: </body>
Body: </html>


Notice that there is no "X-Special" (or HTTP_X_SPECIAL) CGI environment variable listed. Did you get one? If not, why not? Is there perhaps another way to interrogate all http headers in the request for my mod_plsql page?

Thanks,
Jack

p.s. I'm using the latest Fusion MW "Web Tier" version of mod_plsql connecting to a v11.2.0.2 database with the latest v10.1.2.0.9 of the PL/SQL Web Toolkit that came with Web Tier.

Tom Kyte
December 11, 2011 - 3:00 pm UTC

I'll redirect you to the otn.oracle.com discussion forum on things about APEX - they own the mod_plsql module and would be best suited to answer this particular inquiry.

Jack Wells, December 11, 2011 - 3:16 pm UTC

Thanks Tom,

And of course the answer was right there. It turns out that you have to explicitly add support for any custom HTTP headers in the DADS.CONF file in the "PlsqlCGIEnvironmentList" directive. I guess mod_plsql filters out any non-standard HTTP headers for security reasons.

Here's the url in case others are interested:

https://forums.oracle.com/forums/thread.jspa?messageID=3699460#3699460



Tom Kyte
December 11, 2011 - 4:40 pm UTC

thank you very much for the followup, that is great. I really appreciate that.

truly.

protecting files on OHS

A reader, January 21, 2013 - 11:08 pm UTC

Tom:

I have a few static HTML files that are hosted by oracle HTTP server under the /htdocs directory.

These will be accessed directly by user by clicking on a URL. Mod_PLSQL will not be used for these.

User log into a plsql web application using mod_plsql. IF they click on the URL for the file, it will open up for them.


However, with this the file is really public open for anyone who types the URL.

I want to protect the files so they are only be accessible by the users who logged in to app.

I am thinking of protecting the directory in APache so it is only accessible by the database machine (ip address).

Can this be implemented by creating a PLSQL procedure that will run when a user clicks the file URL so that the session is validated and then a redirection happens to the file URL. Would this show the web server that the request is coming from the DB machine ip in the header?

if not, can I change the ip address in the HTTP header request.

If this wo'nt work, can you suggest other possible solutions.

I do not want users to login twice: once to application and once to apache (i.e creating an apache password file)