This document gives a short overview of the security aspects when running a byzcoin node. It is written by one of the main authors of byzcoin, so it should be taken with a big grain of salt. Every contribution is very welcome.
I discuss the following security aspects of running a byzcoin node:
- remote execution
- maliciously inserted code
- DOS attacks against or using the server
- CPU / harddisk
Each node opens two ports:
- one port for node-to-node communication using protobuf-over-tls
- one port for web clients to connect, protected by a valid TLS certificate
TLDR: Look at #14 for proposed fixes.
- 20-02-12 - initial version with list of possible disk-filling attacks
- 20-12-16 - updated version with implemented fixes
Even though the byzcoin node is run in a docker container, the risk of executing non-desired code exists. Usual attacks exploit a buffer overflow or badly tested input variables to make the server execute code from the attacker. For this attack to work, the server software needs to do at least one of the following:
- accept invalid messages over the network that lead to undesired code-paths
- have a code-path that executes external binaries
For 1., the following points need to be taken into account
- using golang makes buffer overflows nearly impossible, as long as the code
doesn't use
unsafe
- network packets need to be safely parsed
Regarding 2., parts of the code that allow binary execution must be specially secured.
To check whether 'unsafe' is used in the code, two parts need to be verified:
- The code of the byzcoin node iteslf, in the
pkg/
-directory - All code in the libraries
To get all the code of all the libraries, it is a big advantage of having a
golang project, as all libraries are available as source code.
When running go build -v -a
, a list of all packages that are included in
the final binary is printed.
Afterwards it's a simple execution of grep
to check where unsafe
is used:
cmd
- the actual command-line tool - no matchespkg
- libraries from DEDIS - no matches
Here the main directories that match have unsafe
operators in their code
, sorted from most concerning to least concerning.
golang.org/x/sys
- golang's system libraries - supposedly they know what they're doinggithub.com/gorilla/[email protected]
- websocket library - the code-path is actively usedgo.etcd.io/[email protected]
- our database that is used internallygithub.com/ethereum/[email protected]
- lots of code that is not in the active code-pathgithub.com/aristanetworks/[email protected]
- library for different things - used extensively in go-ethereumgithub.com/syndtr/[email protected]
- used by go-ethereum, but not in the active code-pathgithub.com/daviddengcn/[email protected]
- output colors to terminal - onlyunsafe
in windows compilationgithub.com/allegro/[email protected]
- conversion from byte to string- should be safe
github.com/prataprc/[email protected]
- bytes2string, seems to be safe
If we suppose that the golang-team knows what they're doing when using
unsafe
, this leaves us with the bbolt
, the websocket
, and the go -ethereum
library and its dependencies.
For the bbolt
library, the extensive use of unsafe
is due to the high
optimizations used in the library.
A full review of this code should be done to be really sure that none of the
unsafe
options in there can be used.
For the websocket
library, the codepath is quite visible and should also be
checked. A first visual inspection shows that there is a potential harm, as
unsafe memory is modified.
The go-ethereum
library has some dependencies that are not in the active
codepath, other are. It would have to be well checked that all unsafe
use
is correct.
All parsing of the incoming network packages is done using the dedis /protobuf
library.
This assures that all incoming data is semantically correct and correspond to
the actual structure requested by the code.
In the main code there is no call to any go library with the goal of
executing a command.
The only reference to exec.Command
from the golang library is in ufave/cli /build.go
, but this file is marked inactive using +build ignore
.
It is always possible to have somebody insert code that will trigger a remote
execution possibility for an attacker.
Contrary to node
, where thousands of packages are used to build a single
application, golang uses much less dependencies.
The total list of external (non-system) libraries used can be found in
Appendix C.
The code of the byzcoin node itself is only updated after a code-review from
the C4DT.
The byzcoin service itself is only badly protected against DOS attacks. It is probably quite easy to send requests over WebSockets to spike the CPU to 100%. However, clients without a valid byzcoin wallet cannot fill up the harddisk.
There is the possibility of amplification attacks in the current version of byzcoin because any node can send any request for an existing protocol. However, this touches only the nodes that are signed up for the current chain, not nodes of other chains of arbitrary IP addresses. For more details, see Appendix B - Refuse non-byzcoin nodes.
As the node is open to all clients, and they can ask any request to the node , it is very easy to have the CPU going at 100%. Currently we have no plan to remove that problem. Should it come to pass that these attacks multiply, something like in Appendix C - WebSocket shutdown would need to be implemented.
Each service in a byzcoin is open to unvalidated clients through a WebSocket interface. As there is no rate limiting on calling the service endpoints, all of them can be used to create a high CPU load on the server. The issue dedis/cothority#2207 describes a list of service endpoints that should be amended:
- byzcoin
- AddTransaction - can fill disk and blockchain with invalid transaction
- skipchain
- StoreSkipBlock - can fill disk with the creation of new blockchains
In addition to services, byzcoin has a number of protocols that need to be run in order to work correctly. Since the implementation of dedis/cothority#2204, no amplification attacks to random IP addresses are possible anymore.
- byzcoinx
- skipchain
- ProtocolExtendRoster
- ProtocolGetBlocks
- blscosi
- blscosi - deprecated - #13
- bdnprotocol
- messaging
- broadcast
- propagation
While the main code should be safe from attacks, the code in go.etcd.io /bbolt
and github.com/gorilla/websocket
should be reviewed with regard to
the use of the unsafe
keyword.
Currently anybody can send invalid ClientTransactions and thus fill up the blockchain. The following proposal should be implemented: dedis/cothority#2205
If there is a DOS attack on the nodes where invalid clients flood the nodes with bogous requests, the following might be needed:
- remove the websocket access
- create follower nodes that only reply to requests, but not participate in the consensus
- add authentication to the follower nodes
go build -v -a 2> packages
sort packages | egrep "(gopkg.in|go.etcd.io|go.dedis|github.com)" | \
sed -e "s/\([^\/]*.\)\([^\/]*.\)\([^\/]*\).*/\1\2\3/" | uniq \
| tee packages.external
github.com/BurntSushi/toml
github.com/allegro/bigcache
github.com/aristanetworks/goarista
github.com/c4dt/byzcoin
github.com/cpuguy83/go-md2man
github.com/daviddengcn/go-colortext
github.com/deckarep/golang-set
github.com/ethereum/go-ethereum
github.com/go-stack/stack
github.com/golang/snappy
github.com/gorilla/websocket
github.com/hashicorp/golang-lru
github.com/prataprc/goparsec
github.com/rs/cors
github.com/russross/blackfriday
github.com/shurcooL/sanitized_anchor_name
github.com/syndtr/goleveldb
github.com/urfave/cli
go.dedis.ch/cothority/v3
go.dedis.ch/fixbuf
go.dedis.ch/kyber/v3
go.dedis.ch/onet/v3
go.dedis.ch/protobuf
go.etcd.io/bbolt
gopkg.in/satori/go.uuid.v1
gopkg.in/tylerb/graceful.v1
The list of files using unsafe has been created in the following way:
grep -r '"unsafe"' $( go list -m -f '{{.Dir}}' $( cat packages.external ) ) | grep .go: > unsafe.matches
grep -v Binary unsafe.matches | sed -e "s/.*go.mod.\(.*\):.*//" | uniq
github.com/allegro/[email protected]/bytes.go: "unsafe"
github.com/aristanetworks/[email protected]/test/pretty_test.go: "unsafe"
github.com/aristanetworks/[email protected]/monotime/nanotime.go: _ "unsafe" // required to use //go:linkname
github.com/aristanetworks/[email protected]/key/composite.go: "unsafe"
github.com/aristanetworks/[email protected]/key/hash.go:import "unsafe"
github.com/aristanetworks/[email protected]/areflect/force.go: "unsafe"
github.com/aristanetworks/[email protected]/sizeof/sizeof.go: "unsafe"
github.com/aristanetworks/[email protected]/sizeof/sizeof_test.go: "unsafe"
github.com/daviddengcn/[email protected]/ct_win.go: "unsafe"
github.com/ethereum/[email protected]/consensus/ethash/algorithm.go: "unsafe"
github.com/ethereum/[email protected]/consensus/ethash/ethash.go: "unsafe"
github.com/ethereum/[email protected]/swarm/storage/feed/feed.go: "unsafe"
github.com/ethereum/[email protected]/crypto/secp256k1/curve.go: "unsafe"
github.com/ethereum/[email protected]/crypto/secp256k1/panic_cb.go:import "unsafe"
github.com/ethereum/[email protected]/crypto/secp256k1/secp256.go: "unsafe"
github.com/ethereum/[email protected]/core/types/receipt.go: "unsafe"
github.com/ethereum/[email protected]/core/types/block.go: "unsafe"
github.com/ethereum/[email protected]/common/bitutil/bitutil.go: "unsafe"
github.com/ethereum/[email protected]/p2p/discv5/sim_testmain_test.go: "unsafe"
github.com/ethereum/[email protected]/log/handler_go13.go: "unsafe"
github.com/ethereum/[email protected]/eth/tracers/tracer.go: "unsafe"
github.com/gorilla/[email protected]/mask.go:import "unsafe"
github.com/prataprc/[email protected]/scanner.go:import "unsafe"
github.com/syndtr/[email protected]/leveldb/version.go: "unsafe"
github.com/syndtr/[email protected]/leveldb/cache/cache_test.go: "unsafe"
github.com/syndtr/[email protected]/leveldb/cache/cache.go: "unsafe"
github.com/syndtr/[email protected]/leveldb/cache/lru.go: "unsafe"
github.com/syndtr/[email protected]/leveldb/db_test.go: "unsafe"
github.com/syndtr/[email protected]/leveldb/storage/file_storage_windows.go: "unsafe"
go.etcd.io/[email protected]/cmd/bbolt/main.go: "unsafe"
go.etcd.io/[email protected]/bucket.go: "unsafe"
go.etcd.io/[email protected]/db.go: "unsafe"
go.etcd.io/[email protected]/bolt_unix_solaris.go: "unsafe"
go.etcd.io/[email protected]/db_test.go: "unsafe"
go.etcd.io/[email protected]/bolt_unix.go: "unsafe"
go.etcd.io/[email protected]/page.go: "unsafe"
go.etcd.io/[email protected]/bolt_openbsd.go: "unsafe"
go.etcd.io/[email protected]/bolt_arm.go:import "unsafe"
go.etcd.io/[email protected]/bolt_windows.go: "unsafe"
go.etcd.io/[email protected]/freelist.go: "unsafe"
go.etcd.io/[email protected]/node_test.go: "unsafe"
go.etcd.io/[email protected]/tx.go: "unsafe"
go.etcd.io/[email protected]/freelist_test.go: "unsafe"
go.etcd.io/[email protected]/node.go: "unsafe"