I am building a system that will hold sensitive user data.
which means that I need to prevent any access to the state database outside the chaincode process.
also if I am publishing the database as a docker image, how do I make sure that the peer uses that specific database image, and not a tampered one.
How to prevent access to the state database outside the chaincode
process
You need to ensure 2 things:
Data that the chaincode reads cannot be used outside of the chaincode
Data that the chaincode reads cannot be altered, and if it's altered then it can be detected.
The first problem can be mitigated by encrypting the data, and the second problem can be mitigated by having the chaincode attach a MAC (Message Authentication Code) tag to every item it writes, and also validate the MAC tag of any item it reads, and if the tag is invalid then return an error.
Worth to mention that you should MAC the ciphertext and not encrypt the MAC (first encrypt, then MAC).
also if I am publishing the database as a docker image, how do I make
sure that the peer uses that specific database image, and not a
tampered one.
If the chaincode has the MAC key embedded inside of it, then the database image you publish will contain records that the chaincode did not produce (hence, did not attach appropritate MAC tags to it) then it will be detected.
The problem is that a malicious administrator could also provide the peer with a valid database container but from the past.
There is another option you can investigate which is Fabric Private Chaincode which uses the Intel SGX TEE(Trusted Execution Environment) feature.
Related
I would like to leverage Hyperledger Fabric Peers (specifically identities) to communicate data that does not need to be recorded as a world state.
The Private Data Collection seems a step in that direction but everything is ordered and recorded.
Is there a way to send a payload between participants that does not get persisted?
Of course, every parameter sent is recorded in the channel's chain (but not in the world state unless your chaincode specifically does it).
Maybe you can save the payload (encrypted if you need it) in a distributed storage system (IPFS, for instance), share the IPFS hash/index via Fabric and delete from IPFS when it is no longer needed. I don't know if it fits your use case.
Suppose I have started fabric with two peers in a single organization. After running my application/rest-server through composer and submitting transactions. I was able to make changes in the values of Couchdb instance of peer1 by going on the address http://localhost:6984/_utils/#/_all_dbs. Now, the two peers are not in sync with each other - application should throw some error but it isn't. Mostly, because it is getting data just from the first peer i.e. peer1.
So, firstly how can I get data from multiple peers - if I want to get data from peer2 aswell?
Secondly, why it is getting data from state database not from ledger?
Thirdly, data should remain in sync even after committed how can I configure this? if some peer tampered its database it should be notified. I have read consensus part and got that it is for the correct order of transactions and blocks but what if someone tampered with the state database?
If you're able to change the entries in state database for 1 peer, with a strong endorsement policy such as AND, your transactions will fail validation because of difference in the data for the two peers. This is one of the most important pros of decentralized network.
State database and the Ledger are not same thing. this should help you in understanding the differences between the both.
Every participating member of a Hyperledger Fabric network is a known entity per se (since Fabric being a permissioned blockchain). Said that, a change in state database of a single peer will again lead to scenario #1 above, where the Read/Write sets in a transaction won't match for multiple peers (as their state databases contain different values of an asset). This will lead to invalidation of the transactions. Now it just becomes a question of how can the network know about the corrupted peer(and subsequent state db). There can be multiple solutions for the same.
But most importantly, Fabric being a permissioned blockchain network, the state databases must be very strictly access protected and authorized outside of the network too.
the fact that you modified the world db doesn't mean anything. any changes you make to that database are not a representation of the ledger.
The ledger itself, the blocks and the transactions they contain are stored in a physical file. The world state db is simply a collection of the current state for each asset. This is a good design because an application will not care about every state change an item went through, it will only care about the current state. The world state db can easily be recreated whenever there is a need for it.
Now, you should not make any changes directly to to the world state db, because that's useless. Any change needs to go through the proper process, via a proposal submitted by a peer which then goes through the orderer. Only when everything is followed, does a change go onto the ledger and get synced with every peer and the world state db will reflect that.
In terms of where you should get the data, the answer is that it doesn't matter. Each peer will have an exact copy of the ledger so if you get data from peer 1 or 2 is irrelevant, it will be the same thing.
Again, just because you changed the world state, that doesn't mean anything, the ledger is untouched, but your application reports the current state from the world state db, which is now incorrect because of your change.
What should be some of the best practices to follow to avoid bugs and write efficient Hyperledger Fabric Chaincode?
General Guidelines for writing Hyperledger Fabric Chaincodes.
Refer to the below link for a detailed description on the same:
https://gist.github.com/arnabkaycee/d4c10a7f5c01f349632b42b67cee46db
Some steps are concisely mentioned below:
Use Chaincode DevMode
Use Chaincode Logging
Using logging is simple and easy. Use Fabric's inbuilt logger. Fabric provides logging mechanism as follows:
For Golang: https://godoc.org/github.com/hyperledger/fabric/core/chaincode/shim#ChaincodeLogger
For NodeJS: https://fabric-shim.github.io/Shim.html#.newLogger__anchor
For Java: You can use any standard logging framework like Log4J
Avoid using Global Keys - Hyperledger Fabric uses an Optimistic Locking Model while committing transactions. In the two-stage process of endorsement & committment, if some versions of the keys that you had read in the Endorsement has changed till your transactions reach the committing stage, you get an MVCC_READ_CONFLICT error. This often is a probability when one or more concurrent transactions are updating the same key.
Use Couch DB Queries wisely
Couch DB Queries DO NOT alter the READ SET of a transaction -
Mongo Queries are for querying the Key Value store aka StateDB only. It does not alter the read set of a transaction. This might lead to phantom reads in the transaction.
Only the DATA that you have stored in the couchDB is searchable - Do not be tempted to search for a key by its name using the MangoQuery. Although you can access the Fauxton console of the CouchDB, you cannot access a key by querying a key by which it is stored in the database. Example : Querying by channelName\0000KeyName is not allowed. It is better to store your key as a property in your data itself.
Write Deterministic Chaincode - Never write chaincode that is not deterministic. It means that if I execute the chaincode in 2 or more different environments at different times, result should always be the same, like setting the value as the current time or setting a random number. For example: Avoid statements like calling rand.New(...) , t := time.Now() or even relying on a global variable (check ) that is not persisted to the ledger.
This is because, that if the read write sets generated are not the same, the Validation System chaincode might reject it and throw an ENDORSEMENT_POLICY_FAILURE.
Be cautions when calling Other Chaincodes from your chaincode. - Invoking a chaincode from another is okay when both chaincodes are on the same channel. But be aware that if it is on the other channel then you get only what the chaincode function returns (only if the current invoker has rights to access data on that channel). NO data will be committed in the other channel, even if it attempts to write some. Currently, cross channel chaincode chaincode invocation does not alter data (change writesets) on the other channel. So, it is only possible to write to one channel at a time per transaction.
Remember to Set Chaincode Execution Timeout - Often it might so happen that during high load your chaincode might not complete its execution under 30s. It is a good practice to custom set your timeout as per your needs. This is goverened by the parameter in the core.yaml of the peer. You can override it by setting the environment variable in your docker compose file :
Example: CORE_CHAINCODE_EXECUTETIMEOUT=60s
Refrain from Accessing External Resources - Accessing external resources (http) might expose vulnerability and security threats to your chaincode. You do not want malicous code from external sources to influence your chaincode logic in any way. So keep away from external calls as much as possible.
I'm aware that read query is a chaincode invocation which reads the ledger current state but does not write to the ledger.
The client app can choose to submit the read-only transaction for ordering, validation, and commit (for auditing purpose)
Question:
Is it possible to read the ledger db without going via the chaincode ?
What prevents someone on channel from directly reading CouchDB (assuming that is the underlying DB used) without using contracts and avoiding recording of reads
Fundamentally, we use an async communication in fabric. The node initiating transaction talks only with the peers synchronously and after that ordering service is initiated which will commit the txn to ledger after all verification check..
Is the following possible ?
node A submits a data to the ledger request for an operation -> which needs to be done by node B.
Is this possible for node A to notify B to check ledger and perform operation and B upon completion notify A to check the updated ledger ?
Is it possible to read the ledger db without going via the chaincode ?
What prevents someone on channel from directly reading CouchDB
(assuming that is the underlying DB used) without using contracts and
avoiding recording of reads
Nothing prevents you from doing it, if you have access to the database itself.
However, the clients usually don't have access to the database and thus the peer (through the chaincode) may enforce selective logic on which clients and what data can be read.
Think of an application server, a servlet container, etc.
The user that browses from the browser doesn't have access to the database the application server uses, right?
A similar thing takes place here.
Fundamentally, we use an async communication in fabric. The node
initiating transaction talks only with the peers synchronously and
after that ordering service is initiated which will commit the txn to
ledger after all verification check..
Strictly speaking, the ordering service does not commit the txn to the ledger, as the ordering service has no ledger. It packages transactions into blocks, then sends the blocks to peers. It is the peers that then validate and commit the block to their own ledgers.
Is this possible for node A to notify B to check ledger and perform
operation and B upon completion notify A to check the updated ledger ?
You need the client SDK to orchestrate all of these. User Chaincodes only run in the context of a client's request.
So, you can have a client perform an operation that submits a transaction, and then the client sends another transaction in which the chaincode checks the current ledger, etc.
Ok, we have a commiting peers - running containers. As i assume, there is an LevelDB or CouchDB database server in containers, that stores world state. As far as i know, data must be available only from blockchain. Why can't I just connect to that database throught container and see the data or change it? If it protected, tell me, please, how protection is creating.
By default, the CouchDB container cannot be accessed from the outside--only the attached peer is allowed to access it. Also, it can be set up with name/password login.
LevelDB does not have its own container.