HTTP Basics

It’s no secret the Internet is everywhere; it powers a large amount of the software we use every single day. An explosion of Application Programming Interfaces (APIs) has significantly increased the number of different services that can be integrated into a single piece of software. In spite of these obvious observations, one thing has remained constant: HTTP (HyperText Transfer Protocol) is the backbone of the Internet. Since the days when browsers were rendering sparkly star backgrounds underneath a myriad of randomly placed images, HTTP has been the protocol responsible for serving up (thankfully, not creating) these web pages.

In order to build applications which are responsive and useful for the end user, it’s important to understand HTTP and the structure of the requests, as well as the responses they generate. Though it may seem trivial for static web sites and applications with minimal functionality, in today’s world of highly integrated web applications understanding the protocol is a necessity. An understanding of HTTP allows other systems and developers to interact with our code in a logical way and accelerates the development process. HTTP is a collection of rules for transferring text, images, videos, and sounds in addition to other file and data types across the web via the transmission of requests and responses. Much like linguistic communication, a browser or server will request a specific resource from a web server; the request will also provide specific details to ensure the response can be delivered the way the requesting server expects. The server receiving the request will attempt to act on the specific details of the request and will report back to the requestor whether or not their request could be fulfilled and return any pertinent information regarding the request. That’s a pretty high level overview of how HTTP generally works; if you would like more detail you can read through the HTTP/1.1 RFC 1.

This chapter will focus on the very basics of HTTP. It is not intended to be an exhaustive resource on the topic, but should provide enough information to gain a better understanding of how OAuth works in the context of an application.

The Problems with Authentication

We all interact with authentication and authorization on a daily basis. In fact, most of the time it has nothing to do with the code you write or the applications you use. If you have a keypad on your garage, a swipe card to enter the office, or a debit card with a Personal Identification Number (PIN) then you are constantly authorizing transactions and actions. We are also aware of the risks and precautions we need to take to ensure that information isn’t disseminated. Losing your swipe card, debit card, or PIN can lead to unauthorized users gaining access to your finances or place of employment. Your garage code can lead to your house being vandalized, burgled, or worse. We treat these scenarios as serious security breaches, as we should. If we’re smart, our PIN isn’t the same as our garage code and doesn’t contain any other personal information that can be used to gain access to other systems.

We have the same risks and should be taking equally effective precautions with interacting with applications on the internet. As more of our daily lives have moved online we appreciate the convenience, but don’t always consider the legitimate security risks (or the impact) breaches can have on our professional and personal lives. What it comes to down to is being as certain as possible that when our online accounts, application accounts and residential security systems authorize access, we’re the person initiating those requests. Imagine the outrage if your bank made your PIN available through relatively little effort. As application developers, we need to take great care to ensure the authorizing information our users trust us with is effectively protected.

Most applications these days require you to login with a user name and password. It’s more common than not for users to have accounts on multiple web sites providing a myriad of different services. Some applications have leveraged this fact and allow you to login with credentials from popular services like Facebook, Twitter, and GitHub–to name a few. While this is usually quite convenient, it should make us wonder “Am I giving my Facebook credentials to another website?”

By now we know this isn’t the case. We see this when we are redirected to the Facebook or Twitter login page to enter our credentials and we understand the results of our authentication attempts are then communicated back to the application we are trying to use. Without this service to handle the interactions between services, it becomes very insecure for two applications to interact with each other.

It’s important to understand this point because it helps to understand the role OAuth fills in our modern day web fueled world. One of the largest fears is that somehow our credentials will be sent across the internet in plain-text. Plain-text information is easily captured by hackers; if our personal password practices are sloppy, this can open anyone up to a world of professional, financial, and even personal pain. You might be wondering who would pass plain-text credentials across the internet in an unencrypted manner. All it takes is one application getting sloppy with your personal information and the havoc mentioned above is right around the corner.

As responsible web developers, we rely on HTTP requests to deliver enough information in the request to properly identify a user (authentication) and allow the application to determine whether the user has access to the requested resource (authorization). When you break it down, developers are responsible for so many difficult things end users take for granted. There is an expectation that other users will not be able to make requests on their behalf, that their user name and password will be properly protected, and that they will be able access everything they have permission to access. No matter your experience level, these are difficult problems and require a great deal of thought and planning to address.

Breaking Down HTTP Requests/Responses

HTTP requests and response can provide a great deal of information to developers allowing us to create secure, personalized experiences for the users of our application. This includes everything from learning whether our requests were successful, to learning what browser or utility is being used to make the request. By learning how these requests are formatted, what content is available and how to access them in PHP, we unlock valuable information for our application.

Requests

The output below is an example of the Headers sent as part of the request. As you can see, the request specifies the format and encoding it expects to receive from the response. It also specifically mentions the host and path where the requestor believes the resource is located.

GET /Protocols/rfc2616/rfc2616.txt HTTP/1.1
User-Agent: HTTPie/0.9.2
Host: www.w3.org
Connection: keep-alive
Accept: */*
Accept-Encoding: gzip, deflate

The response shown below will indicate whether a resource was found on the host and path indicated in the request and will include some additional information about the response. The status code offers a quick, specific update on whether or not the request was successful. It also indicates the format of the response, the length of the response, and some cache information like the last time the page was edited, the date and time of the request, and a date and time for when the results of this request expire.

HTTP/1.1 200 OK
Date: Fri, 18 Dec 2015 04:15:45 GMT
Server: Apache/2
Last-Modified: Tue, 29 Jul 2008 15:34:19 GMT
ETag: "69810-4532b5f92d4c0"
Accept-Ranges: bytes
Content-Length: 432144
Cache-Control: max-age=21600
Expires: Fri, 18 Dec 2015 10:15:45 GMT
P3P: policyref="http://www.w3.org/2014/08/p3p.xml"
Content-Type: text/plain

In the examples above, it’s important to note the headers are sent in plain-text and each header is terminated by a carriage return and new line character ( ). It is possible to inspect these headers in Chrome and Firefox by right clicking on the page and selecting Inspect Element. This will open up the browsers development tools. Once the window opens on the bottom, the Network tab will allow you to see all the HTTP requests that were made to render the page. Clicking on any single request will reveal information about the request, including the Request and Response headers. You can also download browser extensions to directly craft and inspect HTTP requests.

Requests are messages sent from the client to the server and give the server enough information to carry out an action on the supplied resource. The resource is identified by a URI, or Uniform Resource Indicator. A URI has a couple of components: the protocol, the host, and the path. A URL, or Uniform Resource Locator, is a type of URI and has the following format:

{protocol}://{host}{path}{query:optional}{port:optional}

You’ll notice there are place holders for query and port, both of those components aren’t required to form a valid URI. A default port for the specified protocol will be used if it is missing, for HTTP it is port 80. Query is completely optional. The client must provide the server with the resource, the data for the resource, and the action the server should attempt. There are many tools we use everyday that will abstract this step away, for example, a web browser. With a web browser, we provide the resource we’d like the server to retrieve and display for us. We don’t necessarily need to know we’re asking the server to perform a GET action on the resource, but that’s exactly what happens.

While providing the action and resource isn’t overly complicated, it makes sense to take a quick look at how this is formatted.

GET http://facebook.com HTTP/1.1

By looking at this request, one can readily determine what the client is asking the server to do. We’re sending a request to http://facebook.com and asking the server to get or retrieve the resource located at http://facebook.com. If you notice, the HTTP version is also being sent along with the action and the resource. This is explicitly telling the server what version of HTTP to use. Finally, each header in the request is terminated by a CRLF (carriage return line feed). A later section in this chapter will delve into more specific information about the actions a server can understand and how those actions operate.

While the header above will make the request to facebook.com and retrieve the resource, there are other headers that can be sent to protect us, and ensure we only get back the type of resources we expect. Some of these are very important, especially when dealing with unfamiliar APIs, but it’s usually a good practice to include them in any case. I have provided more information on some of these useful headers in the next section.

Useful Headers

Accept

The Accept header tells the server what type of resource the client is willing to accept in the response. This can be very important to ensure the data sent back from the server is not overtly malicious, or unable to be displayed properly by the client. For example, when interacting with an API where the response is expected to be returned in JSON (JavaScript Object Notation), setting the Accept header to application/json will ensure if the response is not JSON, that it will not be returned. Here is an example of a request sent with the Accept header:

GET http://somecoolapi.com/v1/user/1b1c3fe76a HTTP/1.1
Accept: application/json
Accept-Charset

The Accept-Charset header tells the server what character set the client is willing to accept in the response. It is important to understand what the server is sending back and how different character sets might work or not work with your application. It is possible for the server to send back a different character set than you might expect, so if your application is displaying data from the response you should know how to request specific character sets from the server. Here is an example of a request sent with the Accept-Charset header:

GET http://somecoolapi.com/v1/user/1b1c3fe76a HTTP/1.1
Accept-charset: utf-8
Host

The Host header is required with every request and is used to identify the host the request is trying to reach. This header allows allows the request to be sent as a relative path the to the host, though the full resource path can still be sent as well. The Host header will assume the request is being sent to port 80, but a different port can be specified as well. If for some reason, the request does not have an internet host, the header must be sent with an empty value. Here is an example of a request sent with the Host header and a relative path:

GET /v1/user/1b1c3fe76a HTTP/1.1
Host: http://example.com

It’s worth noting this is by no means an exhaustive list, for more information on the types of headers that can be sent with the request take a look at the HTTP 1.1 RFC (RFC-2616).

Response

Once the server receives the request, it attempts to fulfill the request and responds to the client with the results of the request. In the same way that the headers are descriptive of the request, the response sends headers describing the results of the request. As you might expect, a successful request indicates the server was able to locate the resource and perform the specified action on the resource. A request can fail for a number of reasons; it’s possible the resource couldn’t be found, the request wasn’t formatted properly, or the client doesn’t have permission to access the resource. Every request has a status code corresponding to result of the request; they are universally used and understood.

The response gives the client the opportunity to respond to the failure in an appropriate way. For example, in the web browser a request to a missing resource could generate a 404 page. When making a request to a web service it can be used to craft a message in a web environment, throw an Exception, or create a log entry for the errant request. To gain an understanding of how to analyze the HTTP response we’ll look at a few common, meaningful headers as well as how to set server specific headers.

Response Headers

Status Code

The status code is included with every response and its purpose is to communicate whether the request has successful and if not, why it failed. Status codes are a component of the protocol and do not change from server to server, which allows their meanings to be universally understood. The status-line in the response provides the status code and a phrase describing the code. It’s relatively simple, but here is an example of a status line for a successful request:

200 OK
Content-Type

The Content-Type header communicates the content type of the data being returned in the body of the response. When the request specifies an Accepts header, the Content-Type header should match one of the provided values in the request. Here is an example of what the Content-Type header would look like when JSON is returned:

Content-Type: application/json
Content-Length

The Content-Length header communicates the size of the content in the body, in terms of number of bytes. This header prevents you from having to make function calls to figure out the length of the response body. Here is an example of the Content-Length header:

Content-Length: 9720
X-* Type Headers

Any header prefixed with X- is a custom header being used to communicate application or service specific information. This is commonly used with APIs to communicate the rate limit and how many requests have been used against the rate limit. These headers can contain anything the server wishes to communicate back to the client. Here’s an example of the rate limit headers from the Twitter API:

X-Rate-Limit-Limit: 150
X-Rate-Limit-Remaining: 130

Response Body

The response body is the content returned in response and is formatted based on the content type. If we look at our example of the web browser, the content body would be the HTML content the user would expect to see. This is what the user will actually be consuming, while the headers provide information about the response and the body.

Stateless Nature of HTTP

HTTP is stateless, which means every single request is independent of any other requests. Once a login request is processed, HTTP no longer knows anything about the request. It has no idea if the previous request was successful, if a new request is from the same user, or even if the user was logged in. This, of course, requires any state maintenance to be handled by the developer outside of HTTP. To handle this developers often use cookies, sessions, databases, or caching tools. The state retrieved from those tools would need to be explicitly sent with each HTTP request or the application would have to prevent the request from being made if the user is in the incorrect state.

When a user logs into a web application, an HTTP request is made to a resource to ensure the provided credentials match a user in the system. From that point onward the application “remembers” the user is logged in. Imagine if the user had to login to an email system and then re-enter their credentials before opening every email; it would be hard to imagine that email service (or any other service) convincing people to use their site. It’s a pretty ridiculous scenario, right? This is exactly what HTTP requires.

By State we mean an application remembers some details about a client from one request to the next.

The concept is really quite straight-forward, HTTP operates independently of your application or DSL (Domain Specific Language) and won’t understand what “logged in” or “authorized” means in the context of the application. Understanding this also helps you develop intelligently and securely; by trying to make HTTP do something it’s not meant to do, we can put our users’ data at risk.

Verbs and Statuses

If you read the previous section, you read some references to “actions” or HTTP verbs and statuses. Verbs are used by the client to communicate what action the server should take on the resource. Statuses are codes that correspond to phrases to communicate whether or not the request was successful. There are number of statuses which provide a detailed explanation of what happened with the request. These two concepts are very important in understanding how to interact with web services.

Verbs

While there are a handful of verbs, we’re going to take a look at a few of the most commonly used verbs and explain what they mean in the context of HTTP.

  • GET: The GET verb is a means of retrieving information from the Request-URI. In the cases where the endpoint creates or produces data, the GET request will only return the data being produced. When there is a need to pass parameters to the endpoint, these are passed through a query string. In the endpoint www.example.com/index.php?id=1&group_id=5, the query string starts at the ? character and contains everything to the right of that character (?id=1&group_id=5 in this specific case). The values in the query string are a key/value pair separated by an =. Multiple pairs are separated with a & or &.
  • POST: The POST verb is intended as a way to create a new resource on the server. This is commonly used in web forms to send the form data to the server where it will be stored. The server defines the means in which the data will be stored and the verb is used as a method of informing the server it should execute the storage process. Parameters for a POST request are not appended to the Request-URI, but are instead sent over as POST fields.
  • PUT: The PUT verb is used as a method to update an existing resource on the server. For example, when a user fills out a registration form to create their account on the server they are using a POST request. However, if any part of that user’s data changes (they get a new phone number perhaps), the modification should happen with a PUT request.
  • DELETE: The DELETE verb is perhaps the most descriptive of the verbs, in the sense it is intended to remove a resource from the server. As in the other requests, the server is responsible for the implementation of the delete, whether that means actually removing it, or moving it to an inaccessible location.

Status Codes

Status codes are three digit codes paired with a phrase explaining whether or not the status completed successfully. The first digit in each three digit code corresponds to a category of statuses. Typically, by looking at the first digit a user can tell whether the response is providing information (100); was successful (200); has been redirected (300); there was an error in the request (400); or there was an error on the server (500). Generally speaking, there is nothing a client can do about a status code in the 500 range; however, with 400 codes the status code can provide information so the client can change/fix their request.

Provided below is a list of status codes and their phrases. The status codes themselves are self-explanatory, but this list should give you an idea of the type of information you can get from the status codes and phrases.

Informational (100)

These indicate a provisional response. They are not supported by HTTP/1.0, because that version of the protocol did not define 1xx codes.

  • 100 Continue
  • 101 Switching Protocols
Success (200)

A 2xx code indicates the server successfully received, understood, and accepted the client request.

  • 200 OK
  • 201 Created
  • 202 Accepted
  • 203 Non-Authoritative Information
  • 204 No Content
  • 205 Reset Content
  • 206 Partial Content
Redirection (300)

Servers use this class of code to indicate to a client further action needs to be taken to fulfill the original request.

  • 300 Multiple Choices
  • 301 Moved Permanently
  • 302 Found
  • 303 See Other
  • 304 Not Modified
  • 305 Use Proxy
  • 307 Temporary Redirect
Client Error (400)

This set of status codes are meant to indicate the client made some sort of error in their request, such as being malformed or not allowed.

  • 400 Bad Request
  • 401 Unauthorized
  • 402 Payment Required
  • 403 Forbidden
  • 404 Not Found
  • 405 Method Not Allowed
  • 406 Not Acceptable
  • 407 Proxy Authentication Required
  • 408 Request Time-out
  • 409 Conflict
  • 410 Gone
  • 411 Length Required
  • 412 Precondition Failed
  • 413 Request Entity Too Large
  • 414 Request-URI Too Large
  • 415 Unsupported Media Type
  • 416 Requested Range Not Satisfiable
  • 417 Expectation Failed
Server Error (500)

A complement to 400 level errors, this status code indicates the server encountered some unexpected condition and could not fulfill the client’s request.

  • 500 Internal Server Error
  • 501 Not Implemented
  • 502 Bad Gateway
  • 503 Service Unavailable
  • 504 Gateway Time-out
  • 505 HTTP Version not supported

While there are certainly more topics that could be covered on HTTP, understanding these concepts will help the remainder of the material make sense. Since OAuth very heavily relies on being able to send headers and understand responses correctly, this material is a great start on the quest to understanding OAuth more completely.


  1. http://phpa.me/http11-rfc2616

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.193.158