The CURL User Agent - php

So how can I check using codeigniter if the client is curl, and then return something different for it?

You can fake the user-agent when using cURL, so it's pointless depending on the user-agent sent when you KNOW it's a cURL request.
For example: I recently wrote an app which gets the pagerank of a url from google. Now Google doesn't like this, so it allows only a certain user agent to access its pagerank servers. Solution? Spoof the user-agent using cURL and Google will be none the wiser.
Moral of the story: cURL user agents are JUST NOT reliable.
If you still want to do this, then you should be able to get the passed user agent just like normal
$userAgent=$_SERVER['HTTP_USER_AGENT'];
EDIT A quick test proved this:
dumpx.php:
<?php
$url="http://localhost/dump.php";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
if($_GET['u']==y) {
curl_setopt($ch, CURLOPT_USERAGENT, "booyah!");
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
//curl_setopt($ch, CURLOPT_CUSTOMREQUEST,'GET');
curl_setopt ($ch, CURLOPT_HEADER, 0);
$exec=curl_exec ($ch);
?>
dump.php:
<?php
var_dump($_SERVER);
?>
Case 1: http://localhost/dumpx.php?u=y
'HTTP_USER_AGENT' => string 'booyah!' (length=7)
Case 2: http://localhost/dumpx.php?u=n
No $_SERVER['HTTP_USER_AGENT']
This proves that there is no default user agent for curl: it will just not pass it in the request header

If you want to detect bots you can not rely on user agent. Best practices are:
Check, that your visitor runs js (not all human users also do).
Check, that your visitor loads additional files linked to webpage (css, images, etc.)
Check visitor timeouts. Humans usualy don't load 10 pages per second.

cURL stands for - Client URL Library and the whole point of it is to be able to make requests that are identical to what a client would make.
The only thing you can do is detect the information that is part of the request, such as the IP address, HTTP Request Headers, cookies/session id cookie, URL (path/page), and any post/get data. If the person using curl to make the request is doing it from an expected IP address and is supplying any expected header/cookie/token/URL/post/get values, then you would not be able to distinguish a curl request from a browser making the request.

You can spoof or set a custom user agent header when using cURL, so it wouldn't be reliable.
Otherwise, you can do this:
if(strtolower($this->input->server('HTTP_USER_AGENT', true)) == 'curl')
{
// Is using cURL
}
This would only occur if the cURL request contained curl in the user agent header.
As far as I know, there is no default user agent set when doing a curl request.

Related

401 Unauthorized when authenticating using referer

I am trying to use an API which says to use it in a custom application to set a custom referer. Here's the official text:
The API requires (if enabled) a token for read operations to be send
to allow request, otherwise "Missing 'key' parameter" message will be
returned.
The security module will use the referrer heading ("referer" in Java,
HTTP_REFERER in PHP) of the request to identify and filter the
authorized domains.
I can currently log in to the web interface by using a special URL provided which seems to set the session and then redirects to the main URL. If I try navigating to the main URL directly without first using the special URL, I get a 401 error, as expected (afterwards, I can just use the main URL)
The key given below the text above is something like: http://example.com/api/?key=secretkeyhere
While I can use the API using the GUI tool in my web browser as described above, I can't figure out how to connect to it programatically. I have tried using both curl in Linux as well as curl in PHP. Both have failed.
curl from terminal:
curl --header http://example.com/api/?key=secretkeyhere http://example.com/api/search?query=terms*
curl in PHP:
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://example.com/api/search?query=terms');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_REFERER, 'http://example.com/api/?key=secretkeyhere');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
$html = curl_exec($ch);
curl_close($ch);
echo "$html";
?>
I continue to get:
Unauthorized This server could not verify that you are authorized to
access the document requested. Either you supplied the wrong
credentials (e.g., bad password), or your browser doesn't understand
how to supply the credentials required.
Am I doing something wrong here? Is the API not set up correctly? I've read the man page for cURL and it seems like this is exactly what I should be doing.

How can I call a SAS Stored Process from CURL within PHP?

I want to build a web application that calls a SAS stored process and prints the results. I want the authentication to be handled behind the scenes.
The web application is built in PHP and I'll be using CURL to make the request.
Is this possible? What CURL options are necessary?
The proper way to do this (with security in mind) would be to use their ticket API- you can do CURL requests with PHP with a handshake first to eventually get the results of an STP endpoint.
Step1a) POST request .../SASLogon/v1/tickets with a form encoded payload of username and password.
Step1b) Look at response header "Location" (split by "/"[-1]) to get your auth token.
Step2a) Make a POST request to the same first url with the auth token appended at the end- and pass in the body (form encoded) the service url (service=xxx) (which ideally is the .../SASStoredProcess/do) endpoint.
Step2b) parse the response body for your ticket token.
Step3a) Run a request to the service (the .../do?token=[TicketToken]) with a POST payload (form encoded) of _program = STP endpoint
Step3b) Results will be the result of your request.
This probably requires some specific SAS installation config things setup- but is the general ticket handshake (generally- typing from memory, not with example in front of me). SAS is very specific depending on the version and what the install you have is.
You can achieve this with CURL, but in my personal opinion I like using higher level request libraries.
The other answers given are both valid- but auth-behind the scenes I assume you want a proper level of security- passing the username and password in each request is a security risk. Using the ticket system and handshake would be a "better" form solution in my mind.
First ensure your stored process web server is configured correctly by following the instructions located here.
Create a .php file containing the below code.
<?php
$parameters = array('_program' => '/Products/SAS Intelligence Platform/Samples/Sample: Hello World', // PATH TO STORED PROCESS
'_username' => 'mysasusername',
'_password' => '{SAS002}EFC0A34D034F489E2E0E03E840D324D6D30964A3', // ENCODED PASSWORD FROM PROC PWENCODE
'myParam1' => 'abc',
'myParam2' => 123
);
//
// CREATE A NEW CURL INSTANCE AND CONFIGURE IT
//
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://sas.myserver.com/SASStoredProcess/do?");
curl_setopt($ch, CURLOPT_PORT, 7980); // PORT USED TO MAKE STORED PROCESS REQUESTS
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // DISABLE SSL CERTIFICATE CHECKING - OPTIONAL DEPENDING ON SERVER CERTIFICATE
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); // DISABLE SSL CERTIFICATE CHECKING - OPTIONAL DEPENDING ON SERVER CERTIFICATE
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // STORED PROCESS LOGIN INVOLVES MULTIPLE PAGE REQUESTS
curl_setopt($ch, CURLOPT_COOKIEFILE, ""); // STORED PROCESS LOGIN REQUIRES COOKIES
curl_setopt($ch, CURLOPT_COOKIEJAR, ""); // STORED PROCESS LOGIN REQUIRES COOKIES
curl_setopt($ch, CURLOPT_HEADER, true); // DONT SUPPRESS HTTP HEADER INFO
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // SUPPRESS DIRECTLY PRINTING RESULTS WHEN CURL_EXEC IS RUN.
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,90); // TIMEOUT LIMIT WHILE TRYING TO CONNECT
curl_setopt($ch, CURLOPT_TIMEOUT, 90); // TIMEOUT WHILE WAITING FOR RESPONSE
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($parameters)); // SET THIS OPTION LAST. MUST USE HTTP_BUILD_QUERY CALL ELSE YOU WILL BE PRESENTED WITH LOGIN PAGE
//
// EXECUTE IS AND SAVE THE RESULTS THEN CLOSE THE CURL OBJECT
//
$response = curl_exec($ch) ;
//
// PARSE OUT THE HTTP HEADER VS THE BODY
//
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
$body = substr($response, $header_size);
print $body;
curl_close($ch);
?>
Configure the following:
_username
_password
_program (for this example I've used a sample that comes with SAS)
CURLOPT_URL
CURLOPT_PORT
depending on your site architecture you may require additional CURL options but the above should suffice for most cases
Once you have configured it, enter the URL of the .php file into your browser's address bar. You should see the output:
Hello World!
The PHP code listed used the minimum # of options required to work. It assumes that at some point you may also want to parse the header data to determine the CONTENT-TYPE of the result.
Also, when implementing the above code, be sure that any user credentials are stored securely. It is never a good idea to hardcode user credentials into source code (even if the SAS password has been run through PWENCODE).
For a generic (non-php, command-line) answer, here is a one-liner.
curl -v -L -c cookiefile -b cookiefile \
-d "_program=$STP&_username=$USERNAME&_password=$PASSWORD" \
https://yourdomain.com/SASStoredProcess/do
As discussed here, things to note include:
1) A cookiefile is used so that the session token can be written (-c) and subsequently read (-b) by the SASLogon redirect.
2) The _username and _password parameters are used to authenticate (see docs)
3) -v for verbose logging, -L to tell curl to follow the redirect (SASLogon) location

cuRL returnin 404 error

I`m using cuRL to get some data from remote server... The response is in JSON format..
This is my code:
$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER , 1);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)");
curl_setopt($ch, CURLOPT_URL, 'http://www.myaddress.com/mypage.php');
curl_setopt($ch, CURLOPT_POSTFIELDS, array("id" => $id));
$return = curl_exec($ch);
curl_close($ch);
If I access the link in the browser the page load OK, but if I access through the cuRL return a 404 error...
I can guess a few things that it can be checked from the server side, to show the error.
1) As it is stated in other answers, be sure to set all the necessary headers, you can check them e.g. by firebug, as it is shown in here,
or you can get the headers by php get_headers function.
to set it use
curl_setopt($ch, CURLOPT_HTTPHEADER, array("HeaderName: HeaderValue"));
2) When you open a page in the browser(excluding form submit with post method) it makes a get request, instead of post, so if in the server side it is checked $_GET, then your post request will not be considered.
3) If you sure that it should be a post request(say, it is a form submit), then the following can be a problem: some forms can have hidden fields, that again are being checked in the server, and if they are not set, error can be returned. So, you should look at the source code of the form and add them(if there are any) to your post parameters.
4) if you are submitting a form, be sure to set the submit button with its name and value as well, because similar to hidden fields, this can be checked as well.
5) Cookies can be a problem as well, because by default browser has it , and curl does not. To to able to set and read cookies use this code
// set cookie
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file);
// use cookie
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file);
here, $cookie_file path to the cookies file. Do not know in linux or mac, but in windows be sure to use absolute path to the cookie file.
6) Also, you can set the referer by
curl_setopt($ch, CURLOPT_REFERER, 'http://www.myaddress.com/mypage.php');
EDIT: In case of ajax request you might want to add a header X-Requested-With with value as XMLHttpRequest
It's possible the server check the HTTP Header, it's the case in the majority of case.
So add the same HTTP Header of your browser, verify with Firebug :
curl_setopt($ch, CURLOPT_HTTPHEADER, array('SomeName: SomeValue'));
Probably there is something else the browser is sending your cURL code is not. You can use any of the tools other folks have suggested, Firebug, Wireshark, Fiddler, etc, etc.
What you need to do is add missing pieces to your request to match the browser as closely as possible in the cURL request until the remote page responds with a 200.
I notice you're doing a POST. In many cases what happens with your browser is you visit a page with a GET request. A session is initialized on the remote site and a cookie is saved in your browser with the session id.
This cookie then needs to be supplied along with subsequent POST requests. PHP cURL has many options to support cookies. There may be other requirements such as CSRF tokens and so forth.
Again, reverse-engineering is the key.

Using CURL - Post and redirect help

I've been banging my head against a wall for a few hours now - and it's probably something really obvious I've missed!
I'm trying to connect to a payment service provider (PSP) using CURL, post data and follow the post so the user actually ends up on the PSP's site.
Using the following:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://psp.com/theirpage');
curl_setopt($ch, CURLOPT_REFERER, "http://mysite.com/mypage");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,$params);
curl_setopt($ch, CURLOPT_POST, 1);
$result=curl_exec($ch);
curl_close($ch);
This successfully connects, verifies the data I've passed, but instead of redirecting the user to the PSP, it just loads the HTML on my site. Safe mode is off, and open_basedir is blank.
What am I doing wrong?
CURL would do an internal redirect and it wont have any effect on the user viewing your curl script. Keep in mind that the payment was made by your server NOT the users computer, hence expecting the session to work for the user is incorrect. cURL 'is the browser'.
If you just want a redirect after payment is made via cURL, you will have to do it via header() or by using some JS like window.location.
The curl request is being made from your server, and as such your server is receiving the response page. There's no way to initiate the request from the server and have the client receive the response. Either return the HTML to the user from your site (as you're doing), or make the request from the client's browser using Javascript. Hope that helps

Trying to AVOID an ASP.NET session using cURL

I'm using a web-service from a provider who is being a little too helpful in anticipating my needs. They have given me a HTML snippet to paste on my website, for users to click on to trigger their services. I'd prefer to script this process, so I've got a php script which posts a cURL request to the same url, as appropriate. However, this provider is keeping tabs on my session, and interprets each new request as an update of the first one, rather than each being a unique request.
I've contacted the provider regarding my issue, and they've gone so far as to inform me that their system is working as intended, and that it's impossible for me to avoid using the same ASP.NET session for each subsequent cURL request. While my favored option would be to switch to a different vendor, that doesn't appear to be an option right now. Is there a reliable way to get a new ASP.NET session with each cURL request?
I've tried the following set of CURLOPT's, to no avail:
//initialize curl
$ch = curl_init($url);
//build a string out of the post_vars
$post_str = http_build_query($post_vars);
//set the necessary curl options
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FAILONERROR, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_str);
curl_setopt($ch, CURLOPT_FAILONERROR, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_COOKIESESSION, 1);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_USERAGENT, "UZ_".uniqid());
curl_setopt($ch, CURLOPT_REFERER, CURRENT_SITE_URL."index.php?newsession=".uniqid());
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Pragma: no-cache", "Cache-Control: no-cache"));
//execute the call to the backend script, retrieve the results
$xmlstr = curl_exec($ch);
If cURL isn't helping much, why not try other methods to call the services from your script, like php's file() function, or file_get_contents().
If you see do not see any difference at all, then the service provider might be using your ip to track your requests. Try using some proxy for a test.
Normal Asp.net session is tracked by a cookie called ASP.NET_SessionId. This cookie is sent within the response to your first request. So as long as your curl requests don't send back this asp.net cookie, each of your requests will have no connection to each other. Use the curl -c option to see what cookies are flying in-between you and them. Overriding this cookie with a cookie file should work if you confirm that it is normal asp.net session being used here.
It is quite poor for a service to use session (http has much cleaner ways of maintaining state which ReST exploits) so I wouldn't completely rule out the vendor switch option.
Well given the options you are using, it seems you have covered your basics. Can you find out how their sessions are setup?
If you know how they setup a session, IE what they use (if it is IP or what not) and then you can figure out a work around. Another option is trying to set the cookies in a different cookie file:
CURLOPT_COOKIEFILE - The name of the file containing the cookie data. The cookie file can be in Netscape format, or just plain HTTP-style headers dumped into a file.
But if all they do is check cookies your current code should work. If you can figure out what the cookie's name is, you can pass a custom cookie that is blank with the request to see if that works. But if you can get information out of them on how their session's work, that would be best.
use these two line to handle the session:
curl_setopt($ch, CURLOPT_COOKIEJAR, "path/to/cookies.txt"); // cookies.txt should be writable
curl_setopt($ch, CURLOPT_COOKIEFILE, "path/to/cookies.txt");

Categories