views:

105

answers:

2

I want to let a user of a web app enter a URL and then pass that URL onto curl. I'd rather use curl than Net::HTTP or open-uri. But this poses a security risk. What's the best way to check the URL string and prevent any injection attacks?

I'm thinking of just using a regular expression like this to check for an injection attack:

raise "possible injection attack" if url =~ /[\s']/

and if that check succeeds, then just invoke curl like so

html = `curl '#{url}'`

Is this safe enough?

A: 

Maybe you're better off using a library like libcurl (to avoid having to use shell commands) ?

ChristopheD
Thanks. I'll look into that, but I'm still interested in the answer to my original question as a matter of general technique, since there are a lot of unix tools I would be able to love to reuse from Ruby.
dan
I guess it's probable to assume most popular unix tools will have Ruby bindings for them (I know this is certainly the case with Python).
ChristopheD
Is there something seriously wrong with wanting to use Ruby (or Python) as glue code that invokes and orchestrates small external programs via the shell? It seems that there is a strong bias here against that, although the Unix Philosophy used to encourage this sort of style.
dan
+1  A: 
system("curl", url)

this is safe because parameters are directly passed to the main(argv) of the command rather than being parsed by a command line processor. For example system("echo", "* && echo shenanigan") literally outputs * && echo shenanigan.

Adrian
Thanks. I think `system(cmd [, arg, ...])` is more what I was looking for but you pointed me in the right direction.
dan
True enough, I keep confusing the two: `exec` replaces the current script with the command, while `system` continues the script afterwards. Fix'd.
Adrian
and why is this safe to do?
samg
dan
The command is directly called, imagine calling `main(argv)` with an array of strings, rather than passing a command line to the command line processor. In deed, @dan's example outputs the parameter literally.
Adrian