table of contents
- NAME
- Objective
- Building
- Portable Code in a Portable World
- Global Preparation
- Features libcurl Provides
- Handle the Easy libcurl
- Multi-threading Issues
- When It Doesn't Work
- Upload Data to a Remote Site
- Passwords
- HTTP Authentication
- HTTP POSTing
- Showing Progress
- libcurl with C++
- Proxies
- Persistence Is The Way to Happiness
- HTTP Headers Used by libcurl
- Customizing Operations
- Cookies Without Chocolate Chips
- FTP Peculiarities We Need
- Headers Equal Fun
- Post Transfer Information
- Security Considerations
- Multiple Transfers Using the multi Interface
- SSL, Certificates and Other Tricks
- Sharing Data Between Easy Handles
- Footnotes
other versions
- wheezy 7.26.0-1+wheezy13
conflicting packages
| libcurl-tutorial(3) | libcurl programming | libcurl-tutorial(3) |
NAME¶
libcurl-tutorial - libcurl programming tutorialObjective¶
This document attempts to describe the general principles and some basic approaches to consider when programming with libcurl. The text will focus mainly on the C interface but might apply fairly well on other interfaces as well as they usually follow the C one pretty closely.Building¶
There are many different ways to build C programs. This chapter will assume a UNIX-style build process. If you use a different build system, you can still read this to get general information that may apply to your environment as well.- Compiling the Program
- Your compiler needs to know where the libcurl headers are
located. Therefore you must set your compiler's include path to point to
the directory where you installed them. The 'curl-config'[3] tool can be
used to get this information:
$ curl-config --cflags
- Linking the Program with libcurl
- When having compiled the program, you need to link your
object files to create a single executable. For that to succeed, you need
to link with libcurl and possibly also with other libraries that libcurl
itself depends on. Like the OpenSSL libraries, but even some standard OS
libraries may be needed on the command line. To figure out which flags to
use, once again the 'curl-config' tool comes to the rescue:
$ curl-config --libs
- SSL or Not
- libcurl can be built and customized in many ways. One of
the things that varies from different libraries and builds is the support
for SSL-based transfers, like HTTPS and FTPS. If a supported SSL library
was detected properly at build-time, libcurl will be built with SSL
support. To figure out if an installed libcurl has been built with SSL
support enabled, use 'curl-config' like this:
$ curl-config --featureAnd if SSL is supported, the keyword 'SSL' will be written to stdout, possibly together with a few other features that could be either on or off on for different libcurls.See also the "Features libcurl Provides" further down.
- autoconf macro
- When you write your configure script to detect libcurl and
setup variables accordingly, we offer a prewritten macro that probably
does everything you need in this area. See docs/libcurl/libcurl.m4 file -
it includes docs on how to use it.
Portable Code in a Portable World¶
The people behind libcurl have put a considerable effort to make libcurl work on a large amount of different operating systems and environments.Global Preparation¶
The program must initialize some of the libcurl functionality globally. That means it should be done exactly once, no matter how many times you intend to use the library. Once for your program's entire life time. This is done usingcurl_global_init()
- CURL_GLOBAL_WIN32
- which only does anything on Windows machines. When used on a Windows machine, it'll make libcurl initialize the win32 socket stuff. Without having that initialized properly, your program cannot use sockets properly. You should only do this once for each application, so if your program already does this or of another library in use does it, you should not tell libcurl to do this as well.
- CURL_GLOBAL_SSL
- which only does anything on libcurls compiled and built SSL-enabled. On these systems, this will make libcurl initialize the SSL library properly for this application. This only needs to be done once for each application so if your program or another library already does this, this bit should not be needed.
Features libcurl Provides¶
It is considered best-practice to determine libcurl features at run-time rather than at build-time (if possible of course). By calling curl_version_info(3) and checking out the details of the returned struct, your program can figure out exactly what the currently running libcurl supports.Handle the Easy libcurl¶
libcurl first introduced the so called easy interface. All operations in the easy interface are prefixed with 'curl_easy'.easyhandle = curl_easy_init();
curl_easy_setopt(handle, CURLOPT_URL, "http://domain.com/");
size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp);
curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, &internal_struct);
success = curl_easy_perform(easyhandle);
Multi-threading Issues¶
The first basic rule is that you must never simultaneously share a libcurl handle (be it easy or multi or whatever) between multiple threads. Only use one handle in one thread at any time. You can pass the handles around among threads, but you must never use a single handle from more than one thread at any given time.http://www.openssl.org/docs/crypto/threads.html#DESCRIPTION
http://www.gnu.org/software/gnutls/manual/html_node/Multi_002dthreaded-applications.html
is claimed to be thread-safe already without anything required.
Required actions unknown.
Required actions unknown.
Required actions unknown.
When It Doesn't Work¶
There will always be times when the transfer fails for some reason. You might have set the wrong libcurl option or misunderstood what the libcurl option actually does, or the remote server might return non-standard replies that confuse the library which then confuses your program.Upload Data to a Remote Site¶
libcurl tries to keep a protocol independent approach to most transfers, thus uploading to a remote FTP site is very similar to uploading data to a HTTP server with a PUT request.size_t function(char *bufptr, size_t size, size_t nitems, void *userp);
curl_easy_setopt(easyhandle, CURLOPT_READFUNCTION, read_function);
curl_easy_setopt(easyhandle, CURLOPT_READDATA, &filedata);
curl_easy_setopt(easyhandle, CURLOPT_UPLOAD, 1L);
/* in this example, file_size must be an curl_off_t variable */ curl_easy_setopt(easyhandle, CURLOPT_INFILESIZE_LARGE, file_size);
Passwords¶
Many protocols use or even require that user name and password are provided to be able to download or upload the data of your choice. libcurl offers several ways to specify them.protocol://user:password@example.com/path/
curl_easy_setopt(easyhandle, CURLOPT_USERPWD, "myname:thesecret");
curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, "myname:thesecret");
curl_easy_setopt(easyhandle, CURLOPT_NETRC, 1L);
machine myhost.mydomain.com login userlogin password secretword
curl_easy_setopt(easyhandle, CURLOPT_KEYPASSWD, "keypassword");
HTTP Authentication¶
The previous chapter showed how to set user name and password for getting URLs that require authentication. When using the HTTP protocol, there are many different ways a client can provide those credentials to the server and you can control which way libcurl will (attempt to) use them. The default HTTP authentication method is called 'Basic', which is sending the name and password in clear-text in the HTTP request, base64-encoded. This is insecure.curl_easy_setopt(easyhandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
curl_easy_setopt(easyhandle, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
curl_easy_setopt(easyhandle, CURLOPT_HTTPAUTH,
CURLAUTH_DIGEST|CURLAUTH_BASIC);
HTTP POSTing¶
We get many questions regarding how to issue HTTP POSTs with libcurl the proper way. This chapter will thus include examples using both different versions of HTTP POST that libcurl supports. char *data="name=daniel&project=curl";
curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDS, data);
curl_easy_setopt(easyhandle, CURLOPT_URL, "http://posthere.com/");
curl_easy_perform(easyhandle); /* post away! */
struct curl_slist *headers=NULL; headers = curl_slist_append(headers, "Content-Type: text/xml"); /* post binary data */ curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDS, binaryptr); /* set the size of the postfields data */ curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDSIZE, 23L); /* pass our list of custom made headers */ curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, headers); curl_easy_perform(easyhandle); /* post away! */ curl_slist_free_all(headers); /* free the header list */
struct curl_httppost *post=NULL;
struct curl_httppost *last=NULL;
curl_formadd(&post, &last,
CURLFORM_COPYNAME, "name",
CURLFORM_COPYCONTENTS, "daniel", CURLFORM_END);
curl_formadd(&post, &last,
CURLFORM_COPYNAME, "project",
CURLFORM_COPYCONTENTS, "curl", CURLFORM_END);
curl_formadd(&post, &last,
CURLFORM_COPYNAME, "logotype-image",
CURLFORM_FILECONTENT, "curl.png", CURLFORM_END);
/* Set the form info */
curl_easy_setopt(easyhandle, CURLOPT_HTTPPOST, post);
curl_easy_perform(easyhandle); /* post away! */
/* free the post data again */
curl_formfree(post);
struct curl_slist *headers=NULL;
headers = curl_slist_append(headers, "Content-Type: text/xml");
curl_formadd(&post, &last,
CURLFORM_COPYNAME, "logotype-image",
CURLFORM_FILECONTENT, "curl.xml",
CURLFORM_CONTENTHEADER, headers,
CURLFORM_END);
curl_easy_perform(easyhandle); /* post away! */
curl_formfree(post); /* free post */
curl_slist_free_all(headers); /* free custom header list */
curl_easy_setopt(easyhandle, CURLOPT_HTTPGET, 1L);
Showing Progress¶
For historical and traditional reasons, libcurl has a built-in progress meter that can be switched on and then makes it present a progress meter in your terminal. int progress_callback(void *clientp,
double dltotal,
double dlnow,
double ultotal,
double ulnow);
libcurl with C++¶
There's basically only one thing to keep in mind when using C++ instead of C when interfacing libcurl:class AClass {
static size_t write_data(void *ptr, size_t size, size_t nmemb,
void *ourpointer)
{
/* do what you want with the data */
}
}
Proxies¶
What "proxy" means according to Merriam-Webster: "a person authorized to act for another" but also "the agency, function, or office of a deputy who acts as a substitute for another".- Proxy Options
-
To tell libcurl to use a proxy at a given port number:
curl_easy_setopt(easyhandle, CURLOPT_PROXY, "proxy-host.com:8080");Some proxies require user authentication before allowing a request, and you pass that information similar to this:
curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, "user:password");If you want to, you can specify the host name only in the CURLOPT_PROXY option, and set the port number separately with CURLOPT_PROXYPORT.Tell libcurl what kind of proxy it is with CURLOPT_PROXYTYPE (if not, it will default to assume a HTTP proxy):
curl_easy_setopt(easyhandle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
- Environment Variables
-
libcurl automatically checks and uses a set of environment variables to know what proxies to use for certain protocols. The names of the variables are following an ancient de facto standard and are built up as "[protocol]_proxy" (note the lower casing). Which makes the variable 'http_proxy' checked for a name of a proxy to use when the input URL is HTTP. Following the same rule, the variable named 'ftp_proxy' is checked for FTP URLs. Again, the proxies are always HTTP proxies, the different names of the variables simply allows different HTTP proxies to be used.The proxy environment variable contents should be in the format "[protocol://][user:password@]machine[:port]". Where the protocol:// part is simply ignored if present (so http://proxy and bluerk://proxy will do the same) and the optional port number specifies on which port the proxy operates on the host. If not specified, the internal default port number will be used and that is most likely *not* the one you would like it to be.There are two special environment variables. 'all_proxy' is what sets proxy for any URL in case the protocol specific variable wasn't set, and 'no_proxy' defines a list of hosts that should not use a proxy even though a variable may say so. If 'no_proxy' is a plain asterisk ("*") it matches all hosts.To explicitly disable libcurl's checking for and using the proxy environment variables, set the proxy name to "" - an empty string - with CURLOPT_PROXY.
- SSL and Proxies
-
SSL is for secure point-to-point connections. This involves strong encryption and similar things, which effectively makes it impossible for a proxy to operate as a "man in between" which the proxy's task is, as previously discussed. Instead, the only way to have SSL work over a HTTP proxy is to ask the proxy to tunnel trough everything without being able to check or fiddle with the traffic.Opening an SSL connection over a HTTP proxy is therefor a matter of asking the proxy for a straight connection to the target host on a specified port. This is made with the HTTP request CONNECT. ("please mr proxy, connect me to that remote host").Because of the nature of this operation, where the proxy has no idea what kind of data that is passed in and out through this tunnel, this breaks some of the very few advantages that come from using a proxy, such as caching. Many organizations prevent this kind of tunneling to other destination port numbers than 443 (which is the default HTTPS port number).
- Tunneling Through Proxy
- As explained above, tunneling is required for SSL to work
and often even restricted to the operation intended for SSL; HTTPS.
This is however not the only time proxy-tunneling might offer benefits to you or your application.As tunneling opens a direct connection from your application to the remote machine, it suddenly also re-introduces the ability to do non-HTTP operations over a HTTP proxy. You can in fact use things such as FTP upload or FTP custom commands this way.Again, this is often prevented by the administrators of proxies and is rarely allowed.Tell libcurl to use proxy tunneling like this:
curl_easy_setopt(easyhandle, CURLOPT_HTTPPROXYTUNNEL, 1L);In fact, there might even be times when you want to do plain HTTP operations using a tunnel like this, as it then enables you to operate on the remote server instead of asking the proxy to do so. libcurl will not stand in the way for such innovative actions either!
- Proxy Auto-Config
-
Netscape first came up with this. It is basically a web page (usually using a .pac extension) with a Javascript that when executed by the browser with the requested URL as input, returns information to the browser on how to connect to the URL. The returned information might be "DIRECT" (which means no proxy should be used), "PROXY host:port" (to tell the browser where the proxy for this particular URL is) or "SOCKS host:port" (to direct the browser to a SOCKS proxy).libcurl has no means to interpret or evaluate Javascript and thus it doesn't support this. If you get yourself in a position where you face this nasty invention, the following advice have been mentioned and used in the past:- Depending on the Javascript complexity, write up a script that translates it to another language and execute that.- Read the Javascript code and rewrite the same logic in another language.- Implement a Javascript interpreter; people have successfully used the Mozilla Javascript engine in the past.- Ask your admins to stop this, for a static proxy setup or similar.
Persistence Is The Way to Happiness¶
Re-cycling the same easy handle several times when doing multiple requests is the way to go.HTTP Headers Used by libcurl¶
When you use libcurl to do HTTP requests, it'll pass along a series of headers automatically. It might be good for you to know and understand these. You can replace or remove them by using the CURLOPT_HTTPHEADER option.- Host
- This header is required by HTTP 1.1 and even many 1.0
servers and should be the name of the server we want to talk to. This
includes the port number if anything but default.
- Accept
- "*/*".
- Expect
- When doing POST requests, libcurl sets this header to
"100-continue" to ask the server for an "OK" message
before it proceeds with sending the data part of the post. If the POSTed
data amount is deemed "small", libcurl will not use this header.
Customizing Operations¶
There is an ongoing development today where more and more protocols are built upon HTTP for transport. This has obvious benefits as HTTP is a tested and reliable protocol that is widely deployed and has excellent proxy-support.- CUSTOMREQUEST
- If just changing the actual HTTP request keyword is what
you want, like when GET, HEAD or POST is not good enough for you,
CURLOPT_CUSTOMREQUEST is there for you. It is very simple to use:
curl_easy_setopt(easyhandle, CURLOPT_CUSTOMREQUEST, "MYOWNREQUEST");When using the custom request, you change the request keyword of the actual request you are performing. Thus, by default you make a GET request but you can also make a POST operation (as described before) and then replace the POST keyword if you want to. You're the boss.
- Modify Headers
- HTTP-like protocols pass a series of headers to the server
when doing the request, and you're free to pass any amount of extra
headers that you think fit. Adding headers is this easy:
struct curl_slist *headers=NULL; /* init to NULL is important */ headers = curl_slist_append(headers, "Hey-server-hey: how are you?"); headers = curl_slist_append(headers, "X-silly-content: yes"); /* pass our list of custom made headers */ curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, headers); curl_easy_perform(easyhandle); /* transfer http */ curl_slist_free_all(headers); /* free the header list */... and if you think some of the internally generated headers, such as Accept: or Host: don't contain the data you want them to contain, you can replace them by simply setting them too:headers = curl_slist_append(headers, "Accept: Agent-007"); headers = curl_slist_append(headers, "Host: munged.host.line");
- Delete Headers
- If you replace an existing header with one with no
contents, you will prevent the header from being sent. For instance, if
you want to completely prevent the "Accept:" header from being
sent, you can disable it with code similar to this:
headers = curl_slist_append(headers, "Accept:");Both replacing and canceling internal headers should be done with careful consideration and you should be aware that you may violate the HTTP protocol when doing so.
- Enforcing chunked transfer-encoding
-
By making sure a request uses the custom header "Transfer-Encoding: chunked" when doing a non-GET HTTP operation, libcurl will switch over to "chunked" upload, even though the size of the data to upload might be known. By default, libcurl usually switches over to chunked upload automatically if the upload data size is unknown.
- HTTP Version
-
All HTTP requests includes the version number to tell the server which version we support. libcurl speaks HTTP 1.1 by default. Some very old servers don't like getting 1.1-requests and when dealing with stubborn old things like that, you can tell libcurl to use 1.0 instead by doing something like this:
curl_easy_setopt(easyhandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
- FTP Custom Commands
-
Not all protocols are HTTP-like, and thus the above may not help you when you want to make, for example, your FTP transfers to behave differently.Sending custom commands to a FTP server means that you need to send the commands exactly as the FTP server expects them (RFC959 is a good guide here), and you can only use commands that work on the control-connection alone. All kinds of commands that require data interchange and thus need a data-connection must be left to libcurl's own judgement. Also be aware that libcurl will do its very best to change directory to the target directory before doing any transfer, so if you change directory (with CWD or similar) you might confuse libcurl and then it might not attempt to transfer the file in the correct remote directory.A little example that deletes a given file before an operation:
headers = curl_slist_append(headers, "DELE file-to-remove"); /* pass the list of custom commands to the handle */ curl_easy_setopt(easyhandle, CURLOPT_QUOTE, headers); curl_easy_perform(easyhandle); /* transfer ftp data! */ curl_slist_free_all(headers); /* free the header list */If you would instead want this operation (or chain of operations) to happen _after_ the data transfer took place the option to curl_easy_setopt(3) would instead be called CURLOPT_POSTQUOTE and used the exact same way.The custom FTP command will be issued to the server in the same order they are added to the list, and if a command gets an error code returned back from the server, no more commands will be issued and libcurl will bail out with an error code (CURLE_QUOTE_ERROR). Note that if you use CURLOPT_QUOTE to send commands before a transfer, no transfer will actually take place when a quote command has failed.If you set the CURLOPT_HEADER to 1, you will tell libcurl to get information about the target file and output "headers" about it. The headers will be in "HTTP-style", looking like they do in HTTP.The option to enable headers or to run custom FTP commands may be useful to combine with CURLOPT_NOBODY. If this option is set, no actual file content transfer will be performed.
- FTP Custom CUSTOMREQUEST
- If you do want to list the contents of a FTP directory
using your own defined FTP command, CURLOPT_CUSTOMREQUEST will do just
that. "NLST" is the default one for listing directories but
you're free to pass in your idea of a good alternative.
Cookies Without Chocolate Chips¶
In the HTTP sense, a cookie is a name with an associated value. A server sends the name and value to the client, and expects it to get sent back on every subsequent request to the server that matches the particular conditions set. The conditions include that the domain name and path match and that the cookie hasn't become too old.curl_easy_setopt(easyhandle, CURLOPT_COOKIE, "name1=var1; name2=var2;");
FTP Peculiarities We Need¶
FTP transfers use a second TCP/IP connection for the data transfer. This is usually a fact you can forget and ignore but at times this fact will come back to haunt you. libcurl offers several different ways to customize how the second connection is being made.Headers Equal Fun¶
Some protocols provide "headers", meta-data separated from the normal data. These headers are by default not included in the normal data stream, but you can make them appear in the data stream by setting CURLOPT_HEADER to 1.Post Transfer Information¶
[ curl_easy_getinfo ]
Security Considerations¶
The libcurl project takes security seriously. The library is written with caution and precautions are taken to mitigate many kinds of risks encountered while operating with potentially malicious servers on the Internet. It is a powerful library, however, which allows application writers to make trade offs between ease of writing and exposure to potential risky operations. If used the right way, you can use libcurl to transfer data pretty safely.- Command Lines
- If you use a command line tool (such as curl) that uses
libcurl, and you give options to the tool on the command line those
options can very likely get read by other users of your system when they
use 'ps' or other tools to list currently running processes.
To avoid this problem, never feed sensitive things to programs using command line options. Write them to a protected file and use the -K option to avoid this.
- .netrc
- .netrc is a pretty handy file/feature that allows you to
login quickly and automatically to frequently visited sites. The file
contains passwords in clear text and is a real security risk. In some
cases, your .netrc is also stored in a home directory that is NFS mounted
or used on another network based file system, so the clear text password
will fly through your network every time anyone reads that file!
To avoid this problem, don't use .netrc files and never store passwords in plain text anywhere.
- Clear Text Passwords
- Many of the protocols libcurl supports send name and
password unencrypted as clear text (HTTP Basic authentication, FTP, TELNET
etc). It is very easy for anyone on your network or a network nearby yours
to just fire up a network analyzer tool and eavesdrop on your passwords.
Don't let the fact that HTTP Basic uses base64 encoded passwords fool you.
They may not look readable at a first glance, but they very easily
"deciphered" by anyone within seconds.
To avoid this problem, use HTTP authentication methods or other protocols that don't let snoopers see your password: HTTP with Digest, NTLM or GSS authentication, HTTPS, FTPS, SCP, SFTP and FTP-Kerberos are a few examples.
- Redirects
- The CURLOPT_FOLLOWLOCATION option automatically follows
HTTP redirects sent by a remote server. These redirects can refer to any
kind of URL, not just HTTP. A redirect to a file: URL would cause the
libcurl to read (or write) arbitrary files from the local filesystem. If
the application returns the data back to the user (as would happen in some
kinds of CGI scripts), an attacker could leverage this to read otherwise
forbidden data (e.g. file://localhost/etc/passwd).
If authentication credentials are stored in the ~/.netrc file, or Kerberos is in use, any other URL type (not just file:) that requires authentication is also at risk. A redirect such as ftp://some-internal-server/private-file would then return data even when the server is password protected.In the same way, if an unencrypted SSH private key has been configured for the user running the libcurl application, SCP: or SFTP: URLs could access password or private-key protected resources, e.g. sftp://user@some-internal-server/etc/passwdThe CURLOPT_REDIR_PROTOCOLS and CURLOPT_NETRC options can be used to mitigate against this kind of attack.A redirect can also specify a location available only on the machine running libcurl, including servers hidden behind a firewall from the attacker. e.g. http://127.0.0.1/ or http://intranet/delete-stuff.cgi?delete=all or tftp://bootp-server/pc-config-dataApps can mitigate against this by disabling CURLOPT_FOLLOWLOCATION and handling redirects itself, sanitizing URLs as necessary. Alternately, an app could leave CURLOPT_FOLLOWLOCATION enabled but set CURLOPT_REDIR_PROTOCOLS and install a CURLOPT_OPENSOCKETFUNCTION callback function in which addresses are sanitized before use.
- Private Resources
- A user who can control the DNS server of a domain being
passed in within a URL can change the address of the host to a local,
private address which the libcurl application will then use. e.g. The
innocuous URL http://fuzzybunnies.example.com/ could actually resolve to
the IP address of a server behind a firewall, such as 127.0.0.1 or
10.1.2.3 Apps can mitigate against this by setting a
CURLOPT_OPENSOCKETFUNCTION and checking the address before a connection.
All the malicious scenarios regarding redirected URLs apply just as well to non-redirected URLs, if the user is allowed to specify an arbitrary URL that could point to a private resource. For example, a web app providing a translation service might happily translate file://localhost/etc/passwd and display the result. Apps can mitigate against this with the CURLOPT_PROTOCOLS option as well as by similar mitigation techniques for redirections.A malicious FTP server could in response to the PASV command return an IP address and port number for a server local to the app running libcurl but behind a firewall. Apps can mitigate against this by using the CURLOPT_FTP_SKIP_PASV_IP option or CURLOPT_FTPPORT.
- Uploads
- When uploading, a redirect can cause a local (or remote)
file to be overwritten. Apps must not allow any unsanitized URL to be
passed in for uploads. Also, CURLOPT_FOLLOWLOCATION should not be used on
uploads. Instead, the app should handle redirects itself, sanitizing each
URL first.
- Authentication
- Use of CURLOPT_UNRESTRICTED_AUTH could cause authentication
information to be sent to an unknown second server. Apps can mitigate
against this by disabling CURLOPT_FOLLOWLOCATION and handling redirects
itself, sanitizing where necessary.
Use of the CURLAUTH_ANY option to CURLOPT_HTTPAUTH could result in user name and password being sent in clear text to an HTTP server. Instead, use CURLAUTH_ANYSAFE which ensures that the password is encrypted over the network, or else fail the request.Use of the CURLUSESSL_TRY option to CURLOPT_USE_SSL could result in user name and password being sent in clear text to an FTP server. Instead, use CURLUSESSL_CONTROL to ensure that an encrypted connection is used or else fail the request.
- Cookies
- If cookies are enabled and cached, then a user could craft
a URL which performs some malicious action to a site whose authentication
is already stored in a cookie. e.g.
http://mail.example.com/delete-stuff.cgi?delete=all Apps can mitigate
against this by disabling cookies or clearing them between requests.
- Dangerous URLs
- SCP URLs can contain raw commands within the scp: URL,
which is a side effect of how the SCP protocol is designed. e.g.
scp://user:pass@host/a;date >/tmp/test; Apps must not allow unsanitized
SCP: URLs to be passed in for downloads.
- Denial of Service
- A malicious server could cause libcurl to effectively hang
by sending a trickle of data through, or even no data at all but just
keeping the TCP connection open. This could result in a denial-of-service
attack. The CURLOPT_TIMEOUT and/or CURLOPT_LOW_SPEED_LIMIT options can be
used to mitigate against this.
A malicious server could cause libcurl to effectively hang by starting to send data, then severing the connection without cleanly closing the TCP connection. The app could install a CURLOPT_SOCKOPTFUNCTION callback function and set the TCP SO_KEEPALIVE option to mitigate against this. Setting one of the timeout options would also work against this attack.A malicious server could cause libcurl to download an infinite amount of data, potentially causing all of memory or disk to be filled. Setting the CURLOPT_MAXFILESIZE_LARGE option is not sufficient to guard against this. Instead, the app should monitor the amount of data received within the write or progress callback and abort once the limit is reached.A malicious HTTP server could cause an infinite redirection loop, causing a denial-of-service. This can be mitigated by using the CURLOPT_MAXREDIRS option.
- Arbitrary Headers
- User-supplied data must be sanitized when used in options
like CURLOPT_USERAGENT, CURLOPT_HTTPHEADER, CURLOPT_POSTFIELDS and others
that are used to generate structured data. Characters like embedded
carriage returns or ampersands could allow the user to create additional
headers or fields that could cause malicious transactions.
- Server-supplied Names
- A server can supply data which the application may, in some
cases, use as a file name. The curl command-line tool does this with
--remote-header-name, using the Content-disposition: header to generate a
file name. An application could also use CURLINFO_EFFECTIVE_URL to
generate a file name from a server-supplied redirect URL. Special care
must be taken to sanitize such names to avoid the possibility of a
malicious server supplying one like "/etc/passwd",
"autoexec.bat" or even ".bashrc".
- Server Certificates
- A secure application should never use the
CURLOPT_SSL_VERIFYPEER option to disable certificate validation. There are
numerous attacks that are enabled by apps that fail to properly validate
server TLS/SSL certificates, thus enabling a malicious server to spoof a
legitimate one. HTTPS without validated certificates is potentially as
insecure as a plain HTTP connection.
- Showing What You Do
- On a related issue, be aware that even in situations like
when you have problems with libcurl and ask someone for help, everything
you reveal in order to get best possible help might also impose certain
security related risks. Host names, user names, paths, operating system
specifics, etc (not to mention passwords of course) may in fact be used by
intruders to gain additional information of a potential target.
To avoid this problem, you must of course use your common sense. Often, you can just edit out the sensitive data or just search/replace your true information with faked data.
Multiple Transfers Using the multi Interface¶
The easy interface as described in detail in this document is a synchronous interface that transfers one file at a time and doesn't return until it is done.SSL, Certificates and Other Tricks¶
[ seeding, passwords, keys, certificates, ENGINE, ca certs ]
Sharing Data Between Easy Handles¶
You can share some data between easy handles when the easy interface is used, and some data is share automatically when you use the multi interface.Footnotes¶
- [1]
- libcurl 7.10.3 and later have the ability to switch over to chunked Transfer-Encoding in cases where HTTP uploads are done with data of an unknown size.
- [2]
- This happens on Windows machines when libcurl is built and used as a DLL. However, you can still do this on Windows if you link with a static library.
- [3]
- The curl-config tool is generated at build-time (on UNIX-like systems) and should be installed with the 'make install' or similar instruction that installs the library, header files, man pages etc.
- [4]
- This behavior was different in versions before 7.17.0, where strings had to remain valid past the end of the curl_easy_setopt(3) call.
| 4 Mar 2009 | libcurl |