Rewriting policies on Citrix ADC / NetScaler, different from responder policies, change the content of requests or responses. Responder policies may change every aspect of traffic flowing through the ADC.
Of course, they follow the same logic as all other policies: There is a policy expression and an action. The policy has to be bound to a vServer, globally or to overwrite global.
Let’s try a first policy!
Rewriting policies, in Citrix ADC / NetScaler, can be based on templates. These are the most important ones:
- delete (delete something)
- delete_all (delete all of something)
- delete_http_header (delete an HTTP header)
- insert_after (insert something after …)
- insert_after_all (insert something after all occurrences of …)
- insert_before (insert something after …)
- insert_befoer_all (insert something after all occurrences of …)
- insert_http_header (add an HTTP header)
- replace (replace something)
- replace_all (replace all occurrences of …)
- replace_http_res (replace the entire HTTP response)
Rewriting policies can be found in AppExpert → Rewrite.
Redirecting from simplified URLs to actual ones
Maybe the URL used for selling red content is a bit too complex for users to remember. The real URL is http://192.168.229.100/red.htm. We want to print this to a commercial. There are several problems for users: Users could write /Red.htm. It won’t work if our web-servers are based on UNIX/Linux, as they are case-sensitive. Our users could use /red.html. Won’t work either. In both cases, our users would get a 404 not found. In the end, users won’t buy our red content at all.
I want to print http://192.168.229.100/red to my commercials. It has to be case-insensitive, no file extension. What can we do?
The policy action
AppExpert → Rewrite → Actions
The policy action is of type replace. We want to replace something: The HTTP_REQ_URL. We want to replace it with
Expression to choose target location: HTTP.REQ.URL
Expression to replace with: “/red.htm”
AppExpert → Rewrite → Policies
This action will replace any URL with /red.htm. This will be wrong in most cases, so we need to find a good policy expression.
Requirements had been: We print http://192.168.229.100/red to our commercials. It has to be case-insensitive, there must not be a file extension.
So the policy expression is
. We do this if the HTTP request URL is /red, but we have to make the expression case-insensitive (SET_TEXT_MODE).
Sometimes you won’t be sure whether or not to use quotes. In most cases, quotes could be treated like any character, so too many quotes won’t be an issue from the perspective of syntax, but from perspective functionality only. But the GUI will never accept your input if necessary quotes are missing. So don’t use quotes if you are not sure and add quotes in case of errors.
Binding the policy
AppExpert → Rewrite → Policies
Click the Policy Manager button.
- Select Load Balancing Virtual Server
- Choose the right protocol (in our case HTTP).
- Make sure to use the right Connection Type (request or response)
- Choose the right virtual server
Next you have to select the policy and click bind
- Click the arrow to open the choose policy dialog
- Select the policy.
- Assign a priority. The lower the number, the higher the priority
Surf to 192.168.229.100/rEd. See what happens
We could also have done this, using responder policies. But in the case of responder policies, we would see changes to the URL. Rewriting is absolutely transparent to users.
Hiding the type of server
Let’s press the F12 key and surf to our colour server, in my case http://192.168.229.100 (this will only work with the most popular browsers like FireFox, Internet Exploder or Chromium). Click Network and then the only request visible.
On the right side, you will see several headers, from the request side and the response side. There is a good description of most of these headers on Wikipedia.
I am interested in two headers on the response side: Server and X-Powered-By. They expose way too much of our internal IT. They simply should not be there. Unfortunately, Server is a requirement in RFC 2616:
The Server response-header field contains information about the software used by the origin server to handle the request. The field can contain multiple product tokens (section 3.8) and comments identifying the server and any significant subproducts. The product tokens are listed in order of their significance for identifying the application.
I am not sure, why IETF introduced this header. In most cases, it’s way too verbose. It will enable the bad guys out there to search for a special type of server running on a certain OS, in case they know how to exploit it. In my case, it’s an IIS 7.5, so the webserver has to be either a Windows Server 2008 R2 or a Windows 7 workstation. This line may also contain information about patch-level, kernel version or the php-version in use. Who needs to know, which operating system we are using? Google does some statistics on that, but it’s absolutely useless to users.
The other header is a non-standard header: X-Powered-By. In our case, it is a webserver, able to execute asp-code. Who needs to know, which technology we are using?
While we may simply delete the X-Powered-By header, we have to replace the Server header.
Actions to manipulate headers
We have just two templates: insert-http-header and delete-http-header. Unfortunately there is nothing like delete-http-header, so we have to delete and re-add instead.
Delete X-Powered-By and Server
The type of action is DELETE_HTTP_HEADER, the Header-Name is the header we want to delete. In our case: X-Powered-By and Server.
The policy is simple, the expression should be true. Create policies and bind them. Be sure to select Goto Next! Only the first policy will apply if you don’t. Follow the steps above to create and bind the policy.
The result should look like that
You can clearly see: Server and X-Powered-By are gone. Unfortunately, this does not follow RFCs, as there has to be a server-header. So we have to insert a new server header.
What could have gone wrong?
You could have bound policies to request side, if none of the policies got applied, but hit counters increment. You selected goto end if just one of the policies gets hits.
Inserting a new server header
- Type: INSERT_HTTP_HEADER
- Header-Name: Server
The policy is a simple true value
What could have gone wrong?
You could have bound policies to request side, if the policy does not work, but hit counters increment. You selected goto end in one of the policies before if the policy does not get hit.
You can clearly see: This is an Oracle iPlanet web-server, not am IIS. The information is wrong, as we know, but hey, what’s wrong about cheating to the bad guys (including Google, Bing and more)?
Don’t forget to unbind rewriting policies prior to continuing!