0

I am trying to use reverse proxy to connect to a restful webservice which requires https. Since I am consuming the service from inside an Oracle XE DB, which has issues with newer versions of https, I am trying to a use reverse proxy, so that oracle can connect using http. I decided to go with apache and tried to follow this guide. My httpd.conf contains the following entries:

Listen 8086

RewriteEngine On
ProxyVia On

ProxyRequests Off
SSLProxyEngine On
SSLProxyVerify none 
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
SSLProxyCheckPeerExpire off

<proxy *="">
  Order deny,allow
  Allow from all
</proxy>

ProxyPass        /earthquakes_allday/     https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson
ProxyPassReverse /earthquakes_allday/     https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson
ProxyRemote https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson http://revprox-ip.here:8086

With this entry I was able to issue a request from Firefox using a rest client extension to http://revprox-ip:8086/earthquakes_allday/ and it worked without flaws.

Status Code: 200 OK
Access-Control-Allow-Headers: accept,origin,authorization,content-type
Access-Control-Allow-Methods: *
...

Inside oracle I created the following function to make requests:

FUNCTION make_request (
        p_url            VARCHAR2,
        p_request_type   VARCHAR2,
        p_request_body   CLOB
    ) RETURN CLOB IS

        utl_req         utl_http.req;
        utl_resp        utl_http.resp;
        req_length      BINARY_INTEGER;
        response_body   CLOB;
        resp_length     BINARY_INTEGER;
        buffer          VARCHAR2(2000);
        amount          PLS_INTEGER := 2000;
        offset          PLS_INTEGER := 1;
        ret_code        INTEGER;
        res_clob        CLOB;
    BEGIN
        DBMS_LOB.CREATETEMPORARY(RES_CLOB,TRUE);
        utl_req := utl_http.begin_request(p_url,p_request_type,'http/1.1');
        utl_http.set_cookie_support(true);
        utl_http.set_header(utl_req,'user-agent',user_agent);
        utl_http.set_header(utl_req,'content-type',content_type);
        req_length := dbms_lob.getlength(p_request_body);
        IF
            req_length <= 32767
        THEN
            utl_http.set_header(utl_req,'Content-Length',req_length);
            utl_http.write_text(utl_req,p_request_body);
            -- If Message data more than 32kb   
        ELSIF req_length > 32767 THEN
            utl_http.set_header(utl_req,'transfer-encoding','chunked');
            WHILE ( offset < req_length ) LOOP
                dbms_lob.read(p_request_body,amount,offset,buffer);
                utl_http.write_text(utl_req,buffer);
                offset := offset + amount;
            END LOOP;

        END IF;

        utl_resp := utl_http.get_response(utl_req);
        BEGIN
            LOOP
                utl_http.read_text(utl_resp,buffer);
                dbms_lob.writeappend(res_clob,length(buffer),buffer);
                dbms_output.put_line(buffer);
            END LOOP;

            utl_http.end_response(utl_resp);
        EXCEPTION
            WHEN utl_http.end_of_body THEN
                utl_http.end_response(utl_resp);
            WHEN OTHERS THEN
                utl_http.end_response(utl_resp);
                    --utl_tcp.close_all_connection();
                RAISE;
                ret_code := utl_resp.status_code;
                utl_http.end_response(utl_resp);
                --analyze_response_code(ret_code);
        END;

        RETURN res_clob;
    END;

When I called the function like this:

DECLARE
    my_clob clob;
BEGIN
    MY_CLOB := make_request('http://revprox-ip.here:8086/earthquakes_allday/', 'GET', NULL);
END;

This gives me only the following output:

<html>
<head><title>400 Bad Request</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx/1.13.9</center>
</body>
</html>

Then I tried to use Fiddler in between by adding adding the following to fiddler's rules:

if (oSession.host == "fiddlerhost:8888") {
            oSession.host ="http://revprox-ip.here:8086";
        }

Adding fiddler to the chain causes that calling the webservice from oracle works (reminds me of the observer effect). So how can I resolve this? In the productive environment I won't be able to install fiddler in addition to the reverse proxy.

BSharp
  • 43
  • 1
  • 9
  • I'm guessing that you're doing something incorrectly with the headers, and nginx refuses to accept them. Fiddler or something in between might be transparently correcting them. See this answer for how to get more detailed error messages from your nginx log. https://stackoverflow.com/questions/12315832/how-to-fix-nginx-throws-400-bad-request-headers-on-any-header-testing-tools – kfinity Feb 20 '18 at 18:27
  • For while I thought that apache is corrupting something. But the ''400 Bad Request" messages come from the server and the test requests from my browser went through the reverse proxy without causing this. For me it looks rather like the request that comes out of my oracle db is somehow malformed, but gets corrected when send throught fiddler. I also tried to replace apache with nginx as a reverse proxy, but the result seemed the same. – BSharp Feb 20 '18 at 20:16
  • 1
    Okay, solved it. Installed mod_dumpio. In the log I found "AH02418: HTTP Request Line; Unrecognized protocol 'http/1.1' (perhaps whitespace was injected?)". I changed 'http/1.1' to 'HTTP/1.1' in my pl/sql function. Now it flies. – BSharp Feb 20 '18 at 20:47

1 Answers1

0

Instead of using Apache as a reverse proxy, perhaps you can use stunnel. You don't need to run a full webserver just to get a fully-functional TLS client.

If you run it as an inetd-style service (xinetd or systemd socket activation), then you can use a minimal config file:

setuid  =   nobody
setgid  =   nobody
chroot  =   /var/empty/stunnel

client  =   yes
connect =   your.target.com:1234

You can also tighten up security with a few more global options:

sslVersion  =   TLSv1.2

; https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/

ciphers = ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS

curve   =   secp521r1

If you are running the XE Database on the same server as the stunnel listener then the base url used for utl_http would be http://127.0.0.1:5678; otherwise you would use an stunnel endpoint on a separate host.