Readit News logoReadit News
eveith · 9 years ago
I am not a web development guy, so this question might seem ridiculous: To me, it always seems that there are a lot of hazards in any web development project, security-wise: A number of attacks, be it injections, XSS, etc. When seeing a new web development framework, I always ask myself: Are the basic security concerns known today addressed? How can I make sure that choosing cool web framework in language X doesn't lead me to an unsafe webapp? Perhaps somebody with more knowledge in web development could chime in here and help me; I would really appreciate that.
aban · 9 years ago
I wrote a long reply, but ended up erasing it and I'll just say that many of these vulnerabilities are due to the programmer using one type (i.e. string) to represent all kinds of data that might be malicious and unsanitized, and then losing track of whether a piece of data is safe for use (e.g. to be sent to DB) or not.

I recommend checking out the Yesod web framework [0], which leverages Haskell's strong type system to provide type-safety and a whole range of nice guarantees, including preventing vulnerabilities like the ones you mentioned.

Spock [1] is another cool web framework also written in Haskell that looks quite promising.

[0]: http://www.yesodweb.com/page/about

[1]: https://www.spock.li

iopq · 9 years ago
Yesod doesn't prevent all of them. You can use "javascript:" to still do XSS, last time I checked. This is because that kind of content is valid in HTML... but maybe not what you wanted to happen
SkyMarshal · 9 years ago
This is actually the million dollar question, not remotely ridiculous. A lot of web frameworks are built with ease of use, productivity, and "fun" for developers in mind, but neglect security at the framework level, instead leaving security to be reimplemented by the devs on every new project.

But the whole point of a framework is to encapsulate all the things that you have to implement for every new web project, so you don't have to keep redoing that every time, and can instead focus dev time on new features and unique elements of each individual site. Securing against common vulnerabilities should be part of that.

There are a few frameworks that get this right, Lift (https://liftweb.net/) being the best I know of, designed to eliminate most of the OWASP Top 10 Vulns (https://www.ibm.com/developerworks/library/se-owasptop10/ind...) using Scala's strong type system and a virtual diff architecture similar to now-in-vogue Javascript frameworks like React. Haskell's Yesod framework is, as mentioned above, another good one in this respect.

eveith · 9 years ago
Thank you; these answers have been most insightful! I learned quite a lot from browsing the links.

I am writing "answers", plural, because although I post this as an answer to SkyMarshals text, I also mean the replies by aban, peller, and petilon.

peller · 9 years ago
The canonical resource I'm aware of is the OWASP project.[0-3] Basically though, always escape user-supplied data (and make sure you're correctly escaping it for the contexts of where it ends up[4]), don't roll your own crypto/authentication, and stick to using battle-tested libraries. (If security matters that much to your app, stick to "boring established framework X" and let other people choose "cool new framework Y".)

[0] https://www.owasp.org/index.php/Category:Popular

[1] https://www.owasp.org/index.php/SQL_Injection_Prevention_Che...

[2] https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_P...

[3] https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(...

[4] A good framework, used correctly, should take care of most (all?) escaping for you. For SQL injection, it's the ORM's job. For XSS, anything using a virtual DOM should escape stuff for you (I know React does). CSRF is more to do with session management, which is where using battle-tested auth code comes into play.

andrewstuart2 · 9 years ago
Virtual DOM doesn't really have anything to do with preventing XSS. It's done in angular 1 as well.

Really, it's about taint checking [1]. Distrust all sources of content by default that might have seen user input (or that you know have seen user input), and require explicit trust declarations from the developers to remove taints.

When you're about to use the data (e.g. appending to the DOM), you simply check for tainted data and escape is for the context you're in. Most times in the browser, that just means escaping content that might be valid HTML, but there are probably other contexts that require escaping as well.

[1]https://en.wikipedia.org/wiki/Taint_checking

technion · 9 years ago
There's also that if you're using React (vue, Angular, et al) with a JSON API (as is usually the case) you've also got CSRF forgery dealt with somewhat automatically as well.

For once, modern implementations are actually really helping security.

chias · 9 years ago
In this vein, one thing I'm not seeing (although I haven't finished reading the "book" yet) is built-in CSRF protection.

While not difficult to implement correctly yourself, I've found that applications written on frameworks that don't include this in the box tend to be applications vulnerable to CSRF.

tim333 · 9 years ago
Frameworks vary in how idiot proof they are in terms of security. For example web2py has everything set fairly secure out of the box and you have to go out of your way to break it. Others may require a bit more sense from the developer.
girvo · 9 years ago
It's a fair question, considering things like Cross Site Scripting (XSS) and Cross Site Request Forgery (CSRF) -- especially the latter -- can be mitigated by using a well constructed and tested framework.
EugeneOZ · 9 years ago
Syntax is amazing! Hope (so much) to see it possible on beta soon. Maybe for somebody it's not a new thing, but for me this:

  struct Message {
     contents: String,
  } 
      
  #[put("/<id>", data = "<message>")]
  fn update(id: ID, message: JSON<Message>)
where message is auto-decoded - it's awesome!

jonaf · 9 years ago
Since you mentioned "for somebody it's not a new thing": this looks a lot like Flask, if you're into Python (except for the type safety); I'm sure there's a Ruby equivalent. It looks a lot like Jersey on the JVM (for Scala, Java, etc).

This pattern is really nice for web frameworks. I'm super excited to see it for Rust! To me, this signals that we're getting pretty high up there on the early-adoption curve.

strictfp · 9 years ago
Sorry but I cannot agree. I work on the JVM and this pattern is great for "hello world" webapps but breaks down pretty quickly. When large parts of your logic like metrics, security and routing is being done with metaprogramming you're really doing yourself a disservice.
aaron-lebo · 9 years ago
Edit: should preface this by saying the framework looks really impressive. I've been looking for a Rust web framework to settle on and this is the most appealing.

It's funny to note how much something small like this matters. It's syntax sugar and presentation, but the difference a comment like this has at the top of an HN post vs an ambiguous but detailed discussion about feature x...massive in effect.

It doesn't seem to be the case, but the entire framework under that could be bad yet it's caught mindshare on the basis of routing syntax (one of the smallest worries in a production web application). Wonder how many frameworks have failed just on the basis of not making a similar decisive first impression?

Syntax matters?

steveklabnik · 9 years ago
We're in the process of addressing discoverability of the crates.io ecosystem, which led to this RFC: https://github.com/rust-lang/rfcs/pull/1824

A quote from it:

> By far, the most common attribute people said they considered in the survey was whether a crate had good documentation. Frequently mentioned when discussing documentation was the desire to quickly find an example of how to use the crate.

Open source projects, in a sense, are like startups: if you want to acquire users, your users have to be able to understand the product! A deeply impressive technical project is, well, impressive, but if nobody can figure out how to use it, it's not going to see nearly as much uptake as a technology that's got a clear and easy way to use it.

There's secondary effects too: a project with a slick website like this makes people take it more seriously. It's less likely that someone who put this much effort in is just going to drop it immediately, though of course, that's not an absolute rule.

TL;DR: developers are users too. Developer marketing matters!

EugeneOZ · 9 years ago
API (and modern web servers are API only) should:

1) handle route (read data, transform, prepare other resources, check access rights)

2) generate response with reading/writing to db.

First step is not so primitive. Reading request data is often boilerplate-rich code, so syntax which can remove tons of boilerplate is very welcomed.

amelius · 9 years ago
Personally I don't like domain-specific sugared syntax. I prefer clarity above all, especially since I hope to spend the least possible amount of time in the networking domain, and this means I'd otherwise have to relearn the syntax whenever I have to dig into the code again.
k__ · 9 years ago
Syntax is why sinatra and express got bit.

Just add a callback for your route and off you go.

Deleted Comment

bwblabs · 9 years ago
Indeed way cleaner than Iron in terms of parsing query (int) arguments and JSON post data (BodyParser).
johnwheeler · 9 years ago
One of my influences, Armin Ronacher, has been doing a lot of Rust work lately, so I've been thinking about looking at it more closely since I appreciate his Python tastes.

Is Rust simple and elegant in the sense that Python is? I've also heard it's for systems programming, which makes me think of C and has kept me away from it. I like how I can bang out scripts quickly in Python. Is the same true of Rust?

edit: found this http://lucumr.pocoo.org/2015/5/27/rust-for-pythonistas/

valarauca1 · 9 years ago
I use Rust a lot for my generic scripting around the office. Small tasks like copy a few thousands files, selectively re-naming them based on a group of regexes.

The Regex crate (which I think is being merged with std) uses the same syntax as Python's regexes.

The Path/PathBuf type in std makes manipulating paths easy (and type safe). No more slicing notation/regexes to find where extensions start. Also it handles unix/windows / vs \ for you.

Python DuckTyping slightly drives me insane. What interfaces are/aren't typed feels like Russian roulete. Nothing like the 4000th processed file crashing your script

The real win is compatibility. If you avoid unsafe you don't need to think to port to Linux/MacOS/Windows.

Lastly it's a binary. So to share with a coworker, just copy it. No module management.

steveklabnik · 9 years ago
> (which I think is being merged with std)

It's on that path, but it's unclear if and when a literal merge into std will happen. Right now, the design of 1.0.0 has been accepted, and once that lands and is released, it will move from "the nursery" to the regualr rust-lang org. From there it could go into std, or it may just stay there forever.

burntsushi · 9 years ago
> The Regex crate (which I think is being merged with std)

To add to what Steve said: there are currently no plans to export regex from std.

Manishearth · 9 years ago
> I've also heard it's for systems programming, which makes me think of C and has kept me away from it.

One of its major goals is making systems programming more accessible. So you shouldn't dismiss it because "systems programming = C", it's trying to change that! :)

That's not to say it won't involve learning some systemsy concepts. But it won't be as scary as C.

You can't necessarily bang out scripts quickly. A type system tends to make this task verbose. However, larger applications benefit a lot from that type system.

We've often had feedback from Python/JS shops using Rust that learning Rust had the side effect of teaching them systems programming. I think that's pretty awesome.

johnwheeler · 9 years ago
I guess I'm contrasting Python with my Java experience so far as banging out prototypes quickly.

In Java, I don't think the type system gets in the way so much as its classpath. It's been a long time since I've done Java, but you'd have to get your jars in order and write an ant or maven script to do the compile/run steps (or at least a bash script).

I like that with Python I can just do pip install whatever and begin using the module immediately in my main method. In Java, It's not standard practice to copy jars into the system classpath IIRC, so you'd have to copy them around every time you want to do something new.

I need to investigate Rust's command line interface. Obviously, the more it can get close to

python main.py

vs.

javac -cp foo/Bar.jar:baz/Quux.jar Main.java; java --classpath foo/Bar.jar:baz/Quux.jar Main

the better it will be for this use case I mention.

Thanks to both of you for responding!

stymaar · 9 years ago
> We've often had feedback from Python/JS shops using Rust that learning Rust had the side effect of teaching them systems programming. I think that's pretty awesome.

I'm a self-taught developer who only practiced memory-safe languages before and I never dared trying C because of its reputation of being too difficult. Rust taught me a lot of things about system programming I never though I will learn one day.

A big thank you to the whole Rust team for that !

eutectic · 9 years ago
There's nothing that makes typed languages inherently more verbose; a Haskell script will tend to be substantially shorter than the equivalent Python.

Rust gives you much more control over how your program runs, but this necessarily means paying a price in expressiveness.

cmyr · 9 years ago
I've been using rust to as a more performance-oriented tool alongside python. It _is_ a different tool: there are certain tasks (for an irl example: taking a Unicode data file, parsing its contents, transforming it in some way, and writing it to disk) where python works very well and Rust feels like overkill.

That said, Rust is very elegant for the work it is doing. Rust iterators and iterator adapters are a powerful and clean way of manipulating collections, and the `match` syntax is an elegant way of handling errors and Option types.

Rust isn't a scripting language in terms of its strengths, but it isn't far away in terms of how pleasant it is to read and write. I would definitely suggest taking a look at it next time you run into performance constraints in python: it's easy to create python-native modules & interfaces with tools like rust-cpython (https://github.com/dgrunwald/rust-cpython).

steveklabnik · 9 years ago
Sounds like http://lucumr.pocoo.org/2015/5/27/rust-for-pythonistas/ is a thing you'll want to read. It's from right when 1.0 was released, so some things may have improved in the meantime, but given our backwards compatibility guarantees, nothing should be flat-out wrong.

And some more recent writing from him as well: https://blog.sentry.io/2016/10/19/fixing-python-performance-...

akiselev · 9 years ago
I started out as an assembly programmer and before Rust I was using C/C++ for systems and embedded, Typescript for browser frontend, and Python for everything else. I still use Typescript for the browser and Python for Jupyter (prototyping and ML) but Rust has largely replaced C/C++/Python for most of my work. Elegance and simplicity mean different things to different people but I'll give it a shot.

Unfortunately, Rust doesn't have an interpreter so it's not as great as a general scripting language but realistically, there's only a few extra lines you have to learn (extern crate and fn main() {...} mostly) along with the compilation step. Imports work more or less the same in both languages but I find Cargo to be far superior to pip as a package manager. You won't run into dependency hell very often and deploying a Rust project is very easy.

As far as writing Rust, it has static typing so if you want to carry over your programming style from Python it will take some getting used to. The extra type information in definitions can be annoying at first (especially with generics and iterators) but overall provide an intangible productivity boost with type inference filling in the gap. Rust objects are basically pure data structures without inheritance so you have to get used to thinking in traits. That said, with conversion traits like Into/From and generics with trait bounds, I can write code as if it were a dynamic language with duck typing (once I've defined my types) with just a little extra boiler plate to tell the compiler the similarities between this duck and that duck. For example, you can write a function fn foo<T: ExampleTrait>(T bar) and call it with any argument that implements ExampleTrait or Into<T: ExampleTrait> for quasi duck typing.

Finally, I feel I'm far more productive in Rust than in Python, assuming I don't need any functionality in the Python stdlib not yet implemented as a crate. On average, Rust crates are slightly lower level than Python's libraries but I find that using them is no less ergonomic, albeit more verbose. Most of the time, if I haven't made a logic error, any Rust code I compile just works and i don't spend countless hours debugging silly errors like variable name typos or magic object changes. More importantly, in Rust, you can encode a significant fraction of your logic into the type system which will be enforced by the compiler. For example, in my STM32 motor controller, I encode physical units as types so I can't accidentally feed the motor a 1000 volts when I mean 1000 millivolts because the Into<ControlSignal> trait calculates the signal based on the input type.

I would definitely give Rust a shot but don't expect to be as proficient in Rust as quickly as Python. The community is younger (but no less helpful) and the ecosystem is still catching up. Most importantly, don't let Rust's status as a systems programming language deter you. It is a low level language but is a modern language that was designed from the ground up by very smart people who incorporated the lessons of the past. Rust's zero cost abstractions, compiler plugins, and tooling have started to bridge the ergonomics gap between high level scripting languages and system development.

johnwheeler · 9 years ago
Thanks I look forward to checking it out.
aaron-lebo · 9 years ago
It really dedends on what you are doing, but if you are building small scripts that aren't necessarily reliant on specific libraries, Nim is probably better than Rust.

Deleted Comment

eigenrick · 9 years ago
This demonstrates the brilliance of Rust's syntax extensions. Not only is the code more readable and ergonomic, but also type safe.

Errors or mismatches in implementations are caught at compile time, saving minutes (or potentially hours or days) in frustrating debugging.

Nice work! This looks fantastic.

Manishearth · 9 years ago
> This demonstrates the brilliance of Rust's syntax extensions.

Sadly this functionality currently requires nightly or using a code generating build script via syntex :(

(Rocket currently only works with nightly, but someone could pretty easily add a syntex port since the APIs are the same)

With macros 1.1, some of this functionality is available on stable, but not the functionality needed by this. I don't know if we plan a "macros 1.2" that stabilizes tokentree expansion for all decorators (not just type item decorators). ("Macros 2.0" is the final polished version of Rust procedural and regular macros, for which there are concrete plans but it will take time to get to)

erickt · 9 years ago
For those not watching the compiler development traffic, macros 1.1 (which will enable things like #[derive(FromForm))]) could land in stable as soon as 6 weeks from now. We haven't really started thinking about a "macros 1.2" yet, so syntex will still have some use.

If you want to know more about our glorious macros 1.1 future, David Tolnay just have a great meetup talk all about this a few weeks ago:

https://air.mozilla.org/rust-meetup-december-2016-12-15/

halestock · 9 years ago
Are dynamic params enforced at compile time? I.e. will the compiler ensure that the route "/<id>" has a matching id parameter?
sbenitez · 9 years ago
Yes! Here's what happens when you don't do the right thing:

  error: 'id' is declared as an argument...
   --> src/main.rs:8:9
    |
  8 | #[get("/<id>")]
    |         ^^^^

  error: ...but isn't in the function signature.
    --> src/main.rs:9:1
     |
  9  |   fn hello() -> &'static str {
     |  _^ starting here...
  10 | |     "Hello, world!"
  11 | | }
     | |_^ ...ending here

jtmarmon · 9 years ago
that is some truly incredible developer ux
chrismorgan · 9 years ago
The span for the “...but isn't in the function signature” should be just the `()` rather than the whole function.
bfrog · 9 years ago
Fantastic work! Taking full use of syntax extensions for code generation is a clear winner in terms of dealing with what would normally end up being a bunch of copy pasta code.
jonaf · 9 years ago
edit: see replies to my comment. I mistook the Hyper pull request being merged for being in the latest release, but it isn't.

Rocket uses Hyper for its HTTP server. So I checked to see if the Hyper HTTP server was really production-ready. Particularly, if it could handle async IO / solve the C10K problem[0]. It looks like Hyper implemented async IO[1], so it should be adequate for production use in this regard. This is great news for users of Rocket because it means you don't need a separate HTTP framework to run your web service, as you would with, say, Django + gunicorn.

Sure, it's a dependency, but in this case, having a production-ready HTTP server out of the box is really nice!

Having said that, is there any literature on Rocket/hyper for security? The production-ready HTTP server is great, but it also means it has to be prepared to deal with certain security issues, like listening on 0.0.0.0 and handling file uploads. You could put HAproxy/nginx/whatever in front of it, but I think Rust has the potential to supply / manage all of this within one unit and simplify the stack / attack surface area.

[0]: http://www.kegel.com/c10k.html

[1]: https://github.com/hyperium/hyper/pull/778

tatterdemalion · 9 years ago
Hyper is not yet async, the preliminary work in the PR you linked to is for a version which has not been pushed to crates.io and is not finished yet.
bbatha · 9 years ago
Hyper 0.9 is async. It does not use futures/tokio ecosystem so it's ergonomics are weak in places, particularly on the client side. I believe the tokio branch of hyper is basically complete and only waiting on tokio to release.
chias · 9 years ago
Being very excited about another Rust web framework, I've been trying to use this for the last few days. While the basics seem very interesting, there's a few large stumbling blocks ready for anyone who might want to "get serious" with it.

Documentation is very sparse. Indeed, the linked to page seems to be the primary documentation repository. This is particularly painful for a brand new project, because googling is wholly useless at this point (the only relevant results being the linked-to page). You can try to infer things from the API, but there's a lot that I would refer to as "hidden gotchas" which you'll only learn about through experimentation or by reading the source.

For example, consider the FromForm functionality. Does it decode url-encoded values? Turns out the answer is: maybe. If your struct defines the field as a String then the input will be url-decoded, but if you define the field as a str then it won't be. FromForm only works at all if the submission is of content-type 'application/x-www-form-urlencoded', failing entirely 'multipart/form-data' for example -- I have no idea how you're meant to go about parsing a multipart form besides doing it manually using just the raw post-data string as input. Also, good luck parsing anything with a checkbox (as their code example does) -- if the checkbox is checked, no problem, the field is populated with 'true'. But if the checkbox is left unchecked, then you get a parse failure because you're "missing" a field. There may be a way to work around this but if there is it isn't well documented and I haven't read through that part of the rocket source yet.