
Building Web Apps in Go - Trisell
https://astaxie.gitbooks.io/build-web-application-with-golang/content/en/preface.html
======
buro9
The lack of example code in the security section should be a worry to all.

It isn't hard to prevent SQL injection if you use parameterized SQL statement
rather than using string concat, and whilst examples of this are trivial they
shouldn't be skipped.

In the XSS section it mentions filtering and checking inputs, but does not
mention sanitization and does not give any examples. In the aversion to use
any non-standard package it also does not mention
[https://github.com/microcosm-cc/bluemonday](https://github.com/microcosm-
cc/bluemonday) or anything similar (I am the author of bluemonday - a HTML
sanitizer in the same vein as the OWASP Java HTML Sanitizer).

There is some sample code, in the Filtering section, but this only
demonstrates the use of a fixed range of inputs in determining a filter, and
then a regexp to check the input matches a format.

Beyond the security, where the theory is at least known even if a
demonstration on how to implement it is lacking... the entire guide misses out
on demonstrating templates to their fullest, and specifically using a map of
functions to provide the equivalent of Django's TemplateTags.

In fact, the missing link for most Go developers who are building web apps,
and for those coming from outside Go, are template tags. Most Go devs I know
(who seem more systems focused) don't even realise that this stuff exists:
[https://golang.org/src/text/template/examplefunc_test.go](https://golang.org/src/text/template/examplefunc_test.go)

~~~
davexunit
Using string-based templating in general is a really bad practice, as it
leaves the door wide open for XSS, SQL injection, etc. Sanitizing inputs,
while often cited as the proper thing to do, isn't addressing the root
problem: that we're using templating systems that don't use proper data types
and thus can't automatically DTRT when rendering.

See [http://www.more-magic.net/posts/structurally-fixing-
injectio...](http://www.more-magic.net/posts/structurally-fixing-injection-
bugs.html) and [https://www.gnu.org/software/guile/manual/html_node/Types-
an...](https://www.gnu.org/software/guile/manual/html_node/Types-and-the-
Web.html) for further explanation.

~~~
Vendan
Interestingly, html/template does actually handle some stuff like this. Pass
html in a string as a field into html/template, and it'll escape all the html
automatically. In order to get the html to actually render, you have to pass
it in as a `template.HTML`. There are variants of the `HTML` type for
different places, including html attributes and javascript code.

------
BinaryIdiot
This seems pretty good. Two huge red flags in my skimming:

1\. The password storage section where it gives MD5 as an option. MD5 should
_never_ be an option, not even in a simple testing / prototype application.

2\. It actually calls base64 encoding encryption / decryption. This is really
_dangerous_ and outright ___wrong_ __.

So if you ignore security related sections this guide overall seems good.

~~~
Vendan
Also, it talks about salting, but it's NOT a salt, or at least it's a horrible
salt. A true salt should not be reused at all, it should be unique to each
password hash. Generally you see something like '<storedhash> = salt +
hash(salt + password)' so you can recover the salt automatically.

~~~
kyrra
A global salt for all your stores passwords at least prevents generic rainbow
tables from being used against a stolen password database. Salts per password
prevents the same password from having the same hash result in your database.

~~~
bschwindHN
There's really no reason to ever use a global salt, it's not like it's hard to
generate a random one for each user. If you're already putting in the effort
to use salts, might as well go all the way instead of saying "well it's better
than nothing ¯\\_(ツ)_/¯" (I'm not directing this at you in particular, just at
anyone who intentionally takes half-measures when it comes to security)

~~~
z92
Theres always will exist an option of having more security, than whatever is
already providing by any system.

That brings up the question: when, choosing to not include more security,
isn't considered a bug?

~~~
toolz
Not sure where the line is drawn, but it's definitely inclusive of the more
secure option when it can be implemented in <10 LoCs of code simple enough 99%
of the professional dev community can write it.

~~~
Vendan
Even worse, using an actual password hashing lib, i.e.
golang.org/x/crypto/bcrypt, is usually going to take care of it for you. 2
lines of code, 1 to make the hash when the password changes, 1 to check if the
password matches the hash, and you are done!(as the library already generates
and includes random salts in the hash for you)

------
tbiehn
The security section, specifically on encryption, is dangerously misleading.
It really needs an overhaul.

To start with - DES is broken, you cannot use it. It also totally blasts over
important details like -not re-using the same IV- for AES. Really, it should
be updated to use a better higher-level general purpose encrypt/decrypt
library, which handles all the happy primitives in a way that you can't shoot
yourself in the foot.

As for 'base64' being a good encryption algorithm? All the nopes & I can't
evens.

The password stuff is pretty bad too. IDK, needs a re-write.

~~~
elithrar
A fix is unlikely—I raised an issue on this over a year ago and my
recommendations were rebutted: [https://github.com/astaxie/build-web-
application-with-golang...](https://github.com/astaxie/build-web-application-
with-golang/issues/354)

Web apps/services should use gorilla/sessions[1], securecookie[2], and Go's
bcrypt/scrypt libs.

[1]:
[http://www.gorillatoolkit.org/pkg/sessions](http://www.gorillatoolkit.org/pkg/sessions)
[2]:
[http://www.gorillatoolkit.org/pkg/securecookie](http://www.gorillatoolkit.org/pkg/securecookie)

~~~
BinaryIdiot
> A fix is unlikely—I raised an issue on this over a year ago and my
> recommendations were rebutted: [https://github.com/astaxie/build-web-
> application-with-golang...](https://github.com/astaxie/build-web-
> application-with-golang..).

That is incredibly unfortunate especially since much of the guide seems pretty
decent.

~~~
elithrar
I disagree—the guide is Beego centric, and Beego does some peculiar things[1].
I feel like I'm ragging on someone's hard work here, but I take web security
seriously, and I want to make sure frameworks (which are attractive to
newbies) are doing sane things.

[1]:
[https://github.com/astaxie/beego/issues/620](https://github.com/astaxie/beego/issues/620)

~~~
thewhitetulip
meanwhile I started to write my own little book on webapps with Go:
[https://github.com/thewhitetulip/web-dev-golang-anti-
textboo...](https://github.com/thewhitetulip/web-dev-golang-anti-textbook)

~~~
0x434D53
Which also teaches horrible security practices. Pleas also use gorilla/csrf
and not your own brown "solution".

~~~
thewhitetulip
okay, you could be less insulting though

------
echelon
I'm so conflicted by Go. If I want to write a website quickly, I'd use Python.
If I were concerned about performance, I have Java. I write my systems stuff
in C++ (Rust now). Is there a compelling reason for me to even learn Go? Is it
better than Java in some measurable way? Should I take the time to learn it?
Honestly curious.

~~~
latch
I wrote The Little Go book [free], my first Go blog post was in 2011, and a
few of my Go libraries are used by people other than just me.

But Go's not my goto language. I'm a staunch believer in the productivity of
dynamic languages. In my opinion, Go's less than stellar type system and weak
reflection capabilities exasperate this gap, even moreso for most websites /
apis (which deal with impedance mismatch at two boundaries).

But, to answer your question. Consider first that Go's very simple to pick up.
So the investment is small. Second, where I differ from you is on your second
point: Java. I dislike it. It's complicated and verbose and gets in my way.
Rust and Go are both proof that we know how to build better languages now. So,
when I need to share memory across multiple cores and performance is a
concern, I switch to Go because it's fast and simple.

~~~
jonesb6
I actually think Go's simplicity is a weakness because it will only get you so
far. Take web development for example, all the tutorials show json.Unmarshall,
but this one stackoverflow post says I should use json.Decode. Oh shoot now
I'm having all sorts of problems because I don't really understand
json.Decode.

Furthermore I think most people reach for Golang in the beginning because they
want performance. However I've found it incredibly easy to write unperformant
Go.

I think Golang will ultimately be a very important stepping stone in language
development in terms of concurrency, type systems, standard libraries,
deployability, and many other categories. I think a lot of important programs
will be written in it. And ultimately I look forward to how future languages
draw from it.

~~~
shitgoose
"I actually think Go's simplicity is a weakness because it will only get you
so far."

Some may argue that Go's simplicity is a strength. Adding moving parts doesn't
always help.

------
joeblau
Over the previous few weeks, I've seen multiple projects including one
internal project drop Go. There was the widely publicized story [1] where
Dropbox was switching from Go to Rust. More recently one of our backend
engineers who built a prototype in Go told us that they pulled all of the
GoLang code out in favor of C++/Python citing a huge overhead (I don't
remember if it's CPU or Memory footprint). I know a lot of people are touting
the concurrency model, but I've seen so many technical analysis of unfavorable
technical analysis of Go that I'm starting to question whether I should learn
Go or invest my time learning something else?

[1] - [http://www.wired.com/2016/03/epic-story-dropboxs-exodus-
amaz...](http://www.wired.com/2016/03/epic-story-dropboxs-exodus-amazon-cloud-
empire/)

~~~
IshKebab
While the concurrency model _is_ nice (especially waiting on multiple channels
- I haven't found a way to do that nicely in C++), I think there are other
bigger advantages to Go:

* The standard library is _really_ nice. It has almost everything you want and it's written in a clean non-enterprisey way

* It generates a single statically linked binary. Doing this is very difficult in most other languages.

* It's really really easy to cross-compile. Again, often very difficult in other languages (you might even have to compile your own compiler).

* It comes with a built in battle tested HTTP2 server, and a sane TLS library.

* It's a very simple language so it is easy for beginners to pick up, and also easy to read other people's code. Don't underestimate the importance of this - there's nothing worse than writing something awesome in a language that your coworkers find difficult, and then perpetually having to support it.

* The tooling is pretty good.

* Performance is good, and they've done really good work on minimising GC pause lengths.

Of course I wouldn't pretend there aren't downsides ( _cough_ generics), but
they're mostly minor and certainly no worse than you'd have in any other
system (C++/Python sounds like it would have more than its fair share of
issues!).

Edit: Aside from generics, my biggest complaint is the impossibility of RAII.
It's too easy to forget to `close()` things. Most languages suffer from this
though, and at least Go makes some attempt to improve matters with `defer`.

~~~
cm3
> it generates a single statically linked binary. Doing this is very difficult
> in most other languages.

For AOT platforms it's difficult mostly due to glibc. e.g. on FreeBSD and
Linux musl it's trivial to build fully static binaries.

Otherwise all valid statements and Golang is an improvement over other
mainstream languages. So here's some future items for improvement that would
make it even better and well suited for wider use:

* a nicer error handling mechanism, though this may be hard

* dead code elimination. Golang's static binaries are huge compared to fully statically compiled executables for other languages. I suppose the new compiler passes and backend might provide a basis to solve this.

* restore compile speed, which of course was mostly due to previously missing optimizations and simple compiler passes, which were added now and made it slower. Still the Wirth'ian language design allows for much faster compile times than C or C++.

------
brightball
Looks like a great contribution to the community. Major props for freely
releasing it.

Most of the Go references that I tend to come across tend to focus on code,
concurrency and API's without much attention to the full stack web app side.
This definitely helps to fill that gap in the community.

Just flipping through the contents and skimming the chapters, the IDE section
alone is really impressive.

------
melle
This book is open source: [https://github.com/astaxie/build-web-application-
with-golang...](https://github.com/astaxie/build-web-application-with-
golang/tree/master/en)

To those with suggestions related to e.g. security pratices, step up and
contribute!

~~~
brazzledazzle
If the author is rejecting security concerns (as noted elsewhere in the
comments) there's not much point in offering help there right?

------
bsaul
Sad to see things haven't changed much on the sql front. Many web apps don't
care about performance for the language, since the cost of querying the db
will be orders of magnitudes higher anyway. What they want is a simple one
liner to persist object graphs into a DB, because 90% of the code will be glue
code around insert from json, and select to json types of features ( i'm
talking list & forms types of web apps, not the fancy video chat over webrtc
demo).

The fact that this books advertize "build your own orm" solution, with the one
given not even able to select 1-many objects makes me really wonder how in the
world one could recommend go for web apps.

Ps: to get a benchmark on what is the current level of productivity expected
today for enterprise-like web apps, just have a look at a loopback.io demo.
Yes, it's node.js which sucks, but you have to admit that we're pretty far
away from manually mapping result columns to struct properties.

------
konart
Needs much of the proofreading. I'm arrays\slices part, and there are a couple
of mistakes already

Like

// define a slice with 10 elements whose types are bytes var ar = [10]byte
{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}

------
aryehof
I find Go to be a concise and productive language for computing infrastructure
applications, but struggle to apply it to problems with complex domains in
business and industry.

For those, other languages like Java and C# that better support encapsulation
and data/information hiding for the modeling of real-world concepts remain
suited.

I think the problem with a lot of language discussions is really about the
need for many to find the "one true ring" that can be learned and applied
everywhere.

Instead, a polyglot approach surely is the best one?

------
dsies
Another project that was posted on HN se months back: [http://go-
bootstrap.io/](http://go-bootstrap.io/)

I think it serves as a good example of how one can use go for webapp
development.

With that said, after a year+ of writing go in my day to day job, I still
gravitate towards dynamic languages for web application development and leave
go for most systems programming tasks.

------
tuananh
Offtopic: Is there any decent Go boilerplate for building API?

~~~
mholt
net/http: [https://golang.org/pkg/net/http](https://golang.org/pkg/net/http)

I'm not trolling. It seriously is easy enough to crank out a basic web app in
less than a hundred lines of code that runs very well with just the standard
library.

~~~
staticint
While I completely agree that the standard library is all you need in quite a
lot of cases, the parent seems to be asking from more of a _" how do I
structure my application"_ perspective. A tool that generates the boilerplate
necessary to use the standard library effectively in a complete application.
Not just http handlers, but think of the persistence layer, for example. The
standard library does not assist much with the engineering aspect of the job.

~~~
tuananh
true. I have problem when it come to structuring the application so i want a
boilerplate so that I can see what everybody has been doing.

------
jayflux
Are people who are using Go (for web apps) using it with Apache or Nginx? Or
is every go app just using a DIY server? I'm genuinely curious

~~~
chvid
That is a good question; I also wonder what a real world production
environment looks like.

A Go program listening directly to port 80 running as root?

What about virtual hosting, https, load balancing and so on?

~~~
andreynering
Actually, you choose.

I like to use [https://caddyserver.com/](https://caddyserver.com/) as reverse
proxy for the easy setup and buildin Let's Encrypt support. You can also use
Apache or Ngixn if you want.

But you can also bind directly to port 80 if it's a simple app.

------
bpicolo
In multiple languages even. Very cool : )

------
zaroth
There's so much good content here, but it's also very surprising how much of
it is truly a "roll-your-own and hope you get it right" approach.

If you have to write explicit code in each of your postbacks to check a CSRF
token, it's going to happen that not all your posts will end up being
protected. If you have to hand-build SQL queries, it's going to happen that
you'll have injection vulnerabilities. If you are manually generating and
signing cookies, and having to write explicit code to sign them and check
signatures... These are all features that should be done in a core library
which makes sure these things happen all the time, not just when you remember
to, what, copy/paste the code into each of your functions to do it?

There's the overall structure of the code, which seems like it would quickly
devolve into chaos. Looking at Section 4.4 there's a 'login' function which
handles rendering the GET as well as processing the POST just by if/else on
r.Method. You wouldn't want to actually structure a code-base like this,
right? Later on, they do show a 'Beego' based router, which seems a bit more
sane, but I'm really not a fan of 'showing the wrong way first' as a learning
tool.

The particular techniques being used seem very home-grown and not particularly
best practice. To prevent double-submit they add a hidden field with
token=MD5(time.Now) and also save it to "a session cookie on the server side"?
Not quite sure what that means, but I think it's trying to say save the token
on the back-end linked to the session, and then verify a POST, from that page,
on that session, has that token. And then presumably clean up the storage...
The majority of which is not actually coded in the example, making it just a
high level roadmap of what you could do, not a practical working starting
point. But anyway, if your goal is to prevent multiple POSTs per GET, and you
already have a transactional session state for the user, then you do it with a
server-side counter, not a hidden field, and certainly not a "obfuscated"
MD5(time.Now). Even if you have no session state, then the simple answer is to
create session state, not to create another token which does exactly the same
thing as session state, but in a completely insecure manor.

So overall I have a ton of respect for the work that was put into this
document, it tries to cover a lot of material and is very easy to read. But I
think the details also matter and 1) I can't believe this is idiomatic Go for
how to actually route and manage requests, and 2) the entire proposed tool-set
for actual secure processing of Sessions, SQL, CSRF, XSS, etc. seems to be
totally home-grown and not at all production ready.

------
nobullet
I would expect something like Go On Rails (no pun intended). That's where
history repeats.

------
Vendan
Note, in the IDE section: LiteIDE has gocode bundled, and in most cases, you
can leave the GOROOT and such alone. I have yet to need to change it on either
linux or windows.

------
anderspetersson
What's the current state of web frameworks for Go? Is there something similar
to Django or Rails out or in development?

~~~
wiremine
I can't speak to that, but I have seen a few Sinatra/Express like frameworks.
I used Gin [1] for a production project and it held up well under load.

[1] [https://gin-gonic.github.io/gin/](https://gin-gonic.github.io/gin/)

------
rajeemcariazo
The author is the maker of Beego

------
sandra_saltlake
development time and performance that is only slightly slower to write than
Python

------
farslan
The vim section is obsolote. There is no `misc/vim` anymore.

------
aladine
Great book. Thanks

------
sna1l
This is amazing!!

------
gy0857478
thanks for sharing

------
douche
I've got to be honest, when these language shootouts come up (and it feels
like I've read a lot of them this week), it reminds me why I'm pretty happy
working in C#. I've got great tooling, generally good libraries, a pretty
decent core language, and generally, shit just works so I can _get shit done._

Is it super sexy, no. Does it win me Internet Geek Points™, no. It's pretty
much still Windows-only, but fine, that's the world I live in. The foot-guns
are relatively small-caliber, and I've learned enough to avoid pointing most
of them. I can do OOP, I can do functional (maybe not super pure ivory-tower
monad/ADT/pattern-matching sorcery, but whatever - still have F# on my todo-
list...), I can write straight procedural code if I really wanted to. I've
even got a REPL and can use it as a scripting language.

Plus, I have generics :-)

~~~
osweiller
Honest question - what is the point of this comment?

While I understand that HN has quite a population of .NET platform devs these
days, traditionally this sort of noisy comments would be quickly rendered
transparent (this one even claims to justify itself relative to a "language
shootout"....only it's just a page talking about Go best practices, so it is
off the mark). And the "Internet Geek Points™" thing is just nonsensical, and
has become another defensive .NET talking point (e.g. "We're not trend
chasers...now let me tell you how we also incorporate all trends").

I would have ignored it, but the above "language partisan" comment, having
utterly nothing of value to add to the comments, or this story, and being
completely out of context, has been floating on the top, betraying a pretty
profound twist in the saga of HN.

~~~
fauigerzigerk
Combine a momentum oriented society with an up/down vote button on everything
and this is what you get.

Voting based on insightfulness or relevance simply cannot work when only a
small minority can ever be expected to stick to it. We are being conditioned
on picking a side and then boosting that side no matter what.

Voting up a comment that is in disagreement with your own opinion makes it
look like you are losing the debate if being upvoted is generally associated
with being right. So most people won't do it.

I believe the only way to prevent this in a community is to force people to
use only words to express opinions. In my view, voting has no place in
debates. And yes it means that we're not going to get our debates filtered and
ranked according to insightfulness. But at least we're not getting any false
signals based on perverse incentives either.

~~~
bhauer
> _I believe the only way to prevent this in a community is to force people to
> use only words to express opinions. In my view, voting has no place in
> debates. And yes it means that we 're not going to get our debates filtered
> and ranked according to insightfulness. But at least we're not getting any
> false signals based on perverse incentives either._

And yet, I just upvoted your comment because it seemed much easier than typing
a reply to say that your comment was of interest to me and I enjoyed reading
it. But now I've said that as well.

I like having the flexibility to do both, but I recognize the compelling
arguments you've made about the problems with having voting available
everywhere. On HN in particular, I feel the downvote capability should be
further constrained than it is presently (I think it opens at 500 karma
presently).

~~~
infogulch
Perhaps the downvote button should be changed to a flag (essentially how I use
it) which might discourage using it for disagreement. I only downvote a
comment when it is abusive, belligerent, blatantly condescending, or clearly
nonsensical and unwilling to actually converse.

Ideally upvote would only be used for well-stated well-reasoned arguments with
a plausible basis, regardless of the actual position, but I sometimes find
myself upvoting a comment because I agree with it's conclusion. I think the
agree-upvote is lamentable, but unavoidable in general.

Some UI changes might be able to fix the disagree-downvote (i.e. change to
'flag'), but I feel that the agree-upvote is too much a part of human nature
to have an easy fix.

