Hacker Newsnew | comments | show | ask | jobs | submit | zopa's comments login

Like this: http://www.haskell.org/ghc/docs/latest/html/users_guide/ffi-.... Haskell's FFI works both ways.

(It's not free: you need to link in the entire Haskell runtime system, which is not small. But you can absolutely do it.)

-----


Cool, thanks for the link. Didn't know this was possible.

-----


> This behavior isn’t inherently unsafe, after all we had to manually build our exploit string and manually instantiate our class. The problem only comes when we put all of these things together.

This is very much the wrong way to think about security. Weakness will be exploited. An attacker only has to find one path past your defenses; you have to guard every possible door. Saying, "look how strange and unlikely the interaction of these weaknesses was," misses the point. Code interacts lots of ways, and if it hadn't been this interaction, it could have been another.

Treating user data as untrustworthy is a good start, and you should do that. But you also ought to make each piece of your code base secure and robust, even if you can't think of how it would be exploited, now.

-----


That was my implied point of the whole article. An attacker can use your code against you in unexpected ways.

-----


It's probably difficult to think of all of the ways in which your code base can be exploited from the get-go.

-----


> Im not sure about the situation in the US. But the same > should be true to some extend.

My understanding is that it's not true to much of any extent in the US. The contract will generally win. It'll depend on the jurisdiction and the case, but it's certainly not the case that all EULAs are per se invalid. Nor is it the case that "the laws cannot be overwritten with contracts." Overwriting the legal default rules is what contracts do.

-----


Only if those legal "default" rules, are specified as "default"

A good example is rape. It does not make sex illegal, it just makes consent a requirement. There is no analogue for murder, so event consent would not allow murder.

Thats the extend of such liscences: they can ask consent for things that require consent. But most of them are filled with stuff that either does not require consent, or where consent is irrelevent.

But when i hear about the type of frivolent lawsuits, i do believe at least liability is defined very differently. Here companies are not liable for misuse by idiots. If an average person understands you can not microwave your cat, then there is no liability when an idiot does that. On the other hand, companies can not distance themselves from being liable for harm due to defects.

Either case, legal terms are not very relevant either way. Because they do not constitute a proper effort of informing. That last part is very relevant. Implicit terms can not define the context, only try to formalize it.

-----


It's not really anti-competitive, and it's very unlikely to be illegal. It's just a fairly classic natural monopoly.

There's only likely to be one major classified ad company, because advertisers want to use the site with the most users, and users want to use the site with the most classified ads. That's hard for a competitor to break into, not because of anticompetitive behavior by Craigslist, but because of the nature of the market.

As for the law, the general rule of thumb, in the US at least, is that it's not illegal to have a monopoly, but it is illegal to use your monopoly to dominate a second market.

-----


Is it not abuse of your monopoly if you demand that their suppliers do not supply competitors?

Because thats essentially what this "exclusive" liscence entails?

-----


I read it as this posting is exclusive. I can make a similar posting somewhere else. Sure, I can't copy-pasta, but if CraigsList thinks that because I post on their site that I can't post it on other sites as well I would LOVE to see them try to sue me.

-----


You cant copy pasta your own content. I totally agree though: this will never hold up in court.

If they want to "own" user submitted content, they need a signature. Just putting some terms up will not suffice, unless the site "sell us your exclusive content" with big "make CL own this content" buttons.

-----


True. But with very general code, like this library, it would be difficult for unit tests to cover more than a small fraction of the domain.

-----


The Haskell frameworks do this, more or less: www.snapframework.com, for instance.

-----


> "Saying "X types of errors were found" is not as good as saying "the following types of errors were found" and that's just the start."

The blog post is vague, but the paper (also available at the link) isn't. It identifies the particular errors found.

-----


> "Who says that?"

http://news.ycombinator.com/item?id=4137283 comes pretty close to making that claim, and that's just on this page.

> "There's trade offs, multitudes, in choosing paradigm / language. It's never so black and white"

Sometimes, it is. Most people don't use COBOL anymore, with reason; better languages came along. Programming is still a new field in the scheme of things. It would be strange if our languages were perfectly optimized, with no room for improvement without offsetting costs.

> "twits who like to argue more than code"

Some of us like to do both :) But go program; we won't stop you...

-----


Yes, you can write a Query type that is vulnerable to SQL injection, if you want to.

But if you write a secure version, you only have to write it once. You only have to maintain it in one place. You only need to test it in one place. And if you forget to use your secure Query type, anywhere else in your code, the compiler will yell at you. It's a significant advantage.

This is easier to see in a language with a rich, flexible and expressive type system than it is in Java. The writer of the original article used Haskell for a reason.

-----


> But if you write a secure version, you only have to write it once.

> You only have to maintain it in one place.

> You only need to test it in one place.

Again, so this cannot be done in a dynamic language? If it can be done, why bring them up?

> And if you forget to use your secure Query type, anywhere else in your code, the compiler will yell at you. It's a significant advantage.

The only thing the compiler will yell at you is if you passed a type that is not of a Query type. The compiler will not yell at you for getting the current session directly or creating your own jdbc driver for that matter.

-----


> "The only thing the compiler will yell at you is if you passed a type that is not of a Query type. The compiler will not yell at you for getting the current session directly or creating your own jdbc driver for that matter."

In Haskell, I'd have a module, Database, that held all my db code. That module would export functions something like

query :: Query -> DBResult update :: Query -> DBAction -> DBResult

(read those as "query is a function that takes a Query and returns a DBResult.")

In the rest of my program, those functions would be the only way to talk to the database. There's your guarantee.

Could I, rather than using my nice database module, instead drop into IO and write code to do something vicious? Surely. But now we've moved beyond bugs and into active malice.

> "Again, so this cannot be done in a dynamic language? If it can be done, why bring them up?"

It's harder. With duck typing, if it looks like a Query it is a Query, no? Even if it drops your table. I'm no expert on dynamic languages, and I'd believe that there are sophisticated object hierarchies that can do these things (at runtime...), but the original article is empirical evidence that real projects get this wrong.

Really, though, try a language with a modern type system and see for yourself. I know we Haskell users sound like zealots, but the difference between the Java and Haskell type systems truly is night and day.

-----


> In the rest of my program, those functions would be the only way to talk to the database. There's your guarantee. Honest question. Take these pseudo sql calls:

    //Bad Person
    username = "lastname'; drop table user--"
    
    //Good Programmer
    query = "select * from users where name like %[username]%";
    input = {"username":"frank"};
    result = execute(query,input);
    
    //Bad Programmer
    query = "select * from users where name like '%"+username+"%'";
    result = execute(query, {});
	
vs

    //Bad Person
    String username = "lastname'; drop table user--"

    //Good Programmer
    Query q = new Query("select * from users where name like %[username]%");
    Input input = new Input(username);
    q.addInput(input);
    Result r = q.execute();
    
    //Bad Programmer
    Query q = new Query("select * from users where name like '%"+username+"%'");
    Result r = q.execute();
    
	
	
Could you solve this better using a static system? Right now I see no difference between the good and bad

-----


> "Right now I see no difference between the good and bad"

You're building a new query string each time you create a Query object, and concatenating the string onto that. With that approach, each time you build a Query object you have a fresh opportunity to mess up. So you're right that there's no difference between your to cases.

Let's drop my off-the-cuff example and look at how a real library, postgresql-simple, handles the issue:

  query :: (ToRow q, FromRow r) => Connection -> Query -> q -> IO [r]
 
Usage example

  query conn "select x from users where name like ?" (Only username)
Do you see the difference? Instead of sticking the username into the SQL query by hand, we use a query function that takes three parameters: a database handle, a Query with a '?' character, and a thing you want to use in the query. The function takes care of properly escaping the username during interpolation. (The "Only" is just a wrapper to make sure we're handing in a datatype we can query with.)

Notice that because Query is a distinct type from String, just doing

  query conn ("select x from userse where name like" ++ username)
doesn't typecheck. Bad Programmer would have a hard time screwing this up.

The full documentation for postgresql-simple is here: http://hackage.haskell.org/packages/archive/postgresql-simpl...

-----


Sure, and Rails offers a similar syntax:

  User.select('x').where('name like ?', username)
But if your language allows literal string interpolation (as Ruby does), what prevents you from doing this:

query conn ("select x from users where name like #{username}")

How do type-safe languages prevent this?

-----


Query isn't a String. String interpolation[^1] would de-sugar to something like this:

  query conn ("select x from users where name like " ++ username)
++ is a function that expects two Strings. The "select..." stuff isn't a String, quotation marks not withstanding. When we try to hand a Query to ++, the compiler screams bloody murder.

Longer explanation: I suspect the syntax is a bit confusing, since while I keep saying "select ..." is a Query, it looks an awful lot like a String. Here's what's going on. Haskell has a typeclass called IsString. Query is an instance of IsString, as is String.[^2]

Quoted text can represent any instance of IsString. So the compiler sees a function that expects a Query and an IsString of some sort, and through the magic of type inference, it decides that the IsString must be a Query.[^3] And when you try to use a function that concatenates Strings on that Query, it knows that Something's Not Right.

[1]: Haskell doesn't have string interpolation. But if it did, this is how it would work.

[2]: And other instances as well. postgresql-simple actually uses ByteStrings, not Strings, for performance.

[3]: I've fuzzed the evaluation order a bit, for simplicity. In practice the first error reported might be that you've passed 2 arguments to a function that expects 3.

-----


In your static example, "Bad Programmer" would be fine, because the Query constructor does escaping. You could do this in a dynamically typed language too, but notice that you don't, you just use strings. The difference between static and dynamic is that with static typing, you can't compile your incorrect program. With dynamic typing, you find out at run time that you forgot to escape the string (turning it into a Query), when that code actually runs.

-----


I'm admittedly ignorant of any type system newer than C++. In a modern static language, how would you design Query such that any SQL injection is caught at compile-time?

On the dynamic side, Rails (in Ruby) doesn't currently catch SQL injections, but it does catch HTML-escaping injections. It (roughly) tags all strings as tainted by default, and when you send them to the browser, it escapes them. If you want to send literal ampersands, angle brackets, etc., you have to mark them as explicitly safe. Since most of your literal HTML is generated by templates (which themselves distinguish variables from static HTML), you end up with run-time safety unless you actively try to break out of it.

-----


See http://news.ycombinator.com/item?id=4139798

-----


If he builds the final query string before giving it to Query, his valid query parts that rely on not being escaped would also be escaped.

To make a safe query type you'd have to provide non-string primitives to build one, if I understand correctly. You can't allow just a full query string (with all of the injections already in place) to be converted to a Query type (as in his Bad Programmer example).

-----


It's called a deceptive cadence -- that's the I V vi part. The IV is warmup for the V - I cadence that ends it all. "Deceptive" because vi is one note away from I, but in minor, not major.

It's a well-known pattern; sorry the internet let you down.

-----


Perhaps my google-fu was weak back then; searching now I see posts about it on several sites. Ha, there's even a Facebook group called "Stop using the I V vi IV chord progression" (http://www.facebook.com/pages/Stop-using-the-I-V-vi-IV-chord...).

-----


You can switch to the sensitive female chord progression: http://sixfouronefive.blogspot.com/

-----

More

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact

Search: