Sorry if the question title sounds unclear, I'll happily accept suggestions how to make it better.


We are running a rather complicated SCADA/MES system with a Web interface through which users can, beside other things, set values directly to a PLC control system. The topology is m:1:n, which is many clients to one central server to many control point clients (redundancy/availability measures omitted for simplicity).

Most of the data with which the users interact dwell on the front end server which is secured to the best of our expertise, but is still a web server at the end of the day. We want additional level of security for all actions that don't end their live at the server but are propagated to the control clients.

Current setup is synchronous and direct - on request the server connects direct to the control client and relays the request. The control client has a PIN stored by itself, which is kept nowhere else in the system and distributed to the authorized personnel through different channel. User must supply the correct PIN, or the request gets rejected by the control client

Current setup

Planned setup

For latency and topology reasons we are planning to switch to asynchronous indirect connection - the request from a user will be stored in the server database and control clients will query the server regularly for the requests. Everything about this setup is convenient, apart from the security implications - the requests for the control points must be stored somewhere on the server, which makes the PIN option irrelevant.

Planned setup

The question is whether there is an option how to secure the 'channel' from the web client to the control client when the requests are asynchronously relayed through the main server.

One idea I could come up with is to simply XOR the request payload, store it on the server and then XOR it again at the control client. This is doable in browser and I suppose this would give the whole request path about the same security as the pin itself. The problem is, that when the Server DB gets compromised and there are more (than one) requests pending in the relay queue, the nature of the requests (JSON strings) will make it very easy to recover the pin. I guess that Base64ing before XOR won't make it any securer.

Details of interest The requests are in form of very short (max 1 KB) JSON strings. There are max. 1000 control clients and estimated 0 to 5 control requests per control client at any given time. Currently the system is not of much interest to 'third parties' but we don't want to wait to have this assumption refuted.

  • I just found this question by accident. Although I believe that after 11 months you probably went with the solution you propose anyway, I will still ask. How sensitive the PIN is? I never worked with manufacturing systems (MES) but I did with chipcards where the PIN is incredibly sensitive. In the chipcard case the PIN must always be stored and transferred encrypted, but that is made easier by the fact that chipcards store a public key in the chip.
    – grochmal
    Commented Sep 5, 2016 at 21:41
  • @grochmal Well, actually, as this has been shifted to a low priority task, our solution is still suboptimal and we haven't found a really secure solution yet. The PIN in our case is not critically sensitive, yet we are not happy delivering only halfway solutions.
    – Pavel
    Commented Sep 6, 2016 at 6:14

2 Answers 2


Having an asynchronous architecture, where requests get queued into a central location, and are then pulled by clients that live within a trust boundary, is a major security architecture improvement over requiring direct input of a PIN from internet clients that expect a synchronous interaction.

A PIN is useless as a credential and should only be considered as an implementation detail from a security perspective. Expectations for synchronous interaction can limit the kinds of intelligence employed in classifying a particular request as benign or malicious. Push from untrusted into trusted presents a much wider attack surface than pull by trusted from untrusted. And a synchronous architecture in which communication may be transient can make it easy to lose relevant information for post-facto analysis. So, changing all of that is already better.

Still, there are many things that can be done to improve security posture of the human-operated interface-facing interface. I would group them into 3 categories.

  1. user authentication

    Since special authorization is required of the personnel for use of this system, one would love to see a premium put on authentication, of course on the machinery but perhaps even more importantly on the training and awareness for the users themselves.

    The most common and lucrative compromise mechanism, far and away, is phishing. The best case scenario is that these authorized folks, through training and exercises, are able to become deeply attuned to threats of impersonation, and become advocates and agents in the field in discovering and avoiding these threats.

    In terms of authentication machinery, the usual http/tls details apply as a baseline, but there are many options- 2FA, client certificates, live callbacks, rotating credentials, social auth, etc. The technical details to some extent matter less than the engagement and training that occurs with the individuals who will be utilizing them.

  2. data custody

    Commands as issued by authorized users have to be stored securely and with integrity. What goes into durable storage should come out the same way. There are many options for ensuring data-at-rest security, most of which center around encryption of sensitive data at rest, and signing of individual transactions by the users who issued them. To the text of the question, there is no "temporary" when it comes to storage. Anything durably committed may live in that state for a long time.

  3. intelligence

    The system as described has authorized users issuing commands to various control systems. There are likely a wide range of commands, and a large number of legitimate activities that can be directed by those individuals.

    Consider building models supporting classification of commands issued by any one individual. Sequences of commands, timing of command issuance, feedback information consulted, location and times of day- some combination of this metadata can be utilized to develop fingerprints of expected activity from authorized individuals. Request sequences that don't match fingerprints can be flagged for further review and confirmation.

    Relatedly, the control systems have their own views on what constitutes acceptable activity. Consider developing threat models and classification schemes for unacceptable uses of these control systems. The existence of a complete queue and history of commands for an entire plant provides a unique opportunity for this analysis.


You do not need to store the PIN on the webserver database, you only need to store something that will enable you to tell (with very high confidence) that the user did input the correct PIN. Assuming that the PIN is sufficiently long (a twelve digit PIN might work) you could do a classic salt+hash case.

Yet, most PINs are 4 digits, therefore rather useless as an authentication method. Instead you can use a decent authentication method in addition to the PIN (making the PIN to be just a detail of the authentication).

A hundred thatnks to atk for chasing me on the fact on how much a 4 digit PIN is useless as an authentication and how easy it is to brute-force it. Seriously, I learned a lot from writing and rewriting this.

Decent option: Add proper authentication

Add a login and password (passphrase) authentication for the users on the webserver. This authentication can stay only on the webserver.

A user willing to interact with the frontend (at least with the part in which he can alter data) must login first. Note that if the current webserver setup already performs this you can reuse it for this purpose.

Now that you have a proper authentication (the passphrase) you can store the PIN in the webserver's database based on it. You can encrypt the PIN under a key generated from the passphrase. For example using PBKDF2. In other words, on the first request from a user, the webserver will need to talk to the control system and retrieve the PIN. It will then store the PIN in the database as follows:

AES(pbkdf2(user_passphrase), PIN)

The user must provide both: his password/passphrase for the webserver and the PIN to perform the request.

On a following request, the user again needs to supply the passphrase and the PIN. But the webserver can use PBKDF2 on the passphrase and use the generated key to decrypt the record from the database and compare against the provided PIN.

In summary, you add a better security feature (a proper passphrase) in addition to the (quite insecure) PIN. You can (and probably should) allow the user to change his passphrase on the webserver but then you need a way to invalidate the cached encrypted PIN in the database.

Limited option: Trivial hash+salt

The following is how you could perform this by using a sufficiently long PIN (e.g. an alphanumercial PIN of some 12-20 bytes in length would suffice against today's brute-forcing attacks). Note that the hash function selection is important.

On a request from the webserver the control system, instead of sending the PIN, may create a salt concatenate to the PIN and use a cryptographic hash to generate a value. For example the control system may perform something like:

  1. Receives request from server for user Bob;
  2. Generates a random salt (say, 012345667890abcdef);
  3. Retrieves Bob's PIN (say, abdd);
  4. Performs hash <- hash_function(abdd + 012345667890abcdef);
  5. Returns hash and salt to the webserver.

The webserver will store both the salt and the hash in the database. On a request from Bob to the webserver a PIN will be sent, let's call it reqPIN. The server can perform the following to check that the PIN is correct:

  1. Retrieve the salt and hash for Bob from the database;
  2. Preform reqHash <- hash_function(reqPIN + salt);
  3. Compare reqHash with the hash from the database.

If the hashes are equal Bob had input the correct PIN.

If the webserver is compromised, you can just boot another one and ask for new salts and hashes from the control client. Nothing on the webserver database can be used to recover the PIN (not in less than a dozen years of extensive hash crunching at least).


  • The hash_function can be any cryptographic hash and gives you a very small collision chance, which is pretty safe to ignore in practice
  • Hash functions as bcrypt or scrypt are needed (maybe even argon2), these hash functions are expensive computationally, making a brute-force attack much harder. You may also perform the hashing several times, i.e. hash_function(hash_function(hash_function(...)))
  • The salt is needed in case two people have the same PIN and one of them is the attacker. He cannot tell that the other person has the same PIN as himself even in the possession of all hashes. He would need all hashes and all salts, and he still would need to recompute all hash iterations.
  • Hashing PINs is useful if the PIN is sufficiently long. If it is extremely short, like typical 4 digit PINs, then hashing it provides little value - the attacker can brute force it relatively quickly. Even with a long salt.
    – atk
    Commented Sep 7, 2016 at 2:17
  • use bcrypt, scrypt or argon2 instead of sha variants. sha variants are designed to be resource-inexpensive, which is not good when storing data
    – atk
    Commented Sep 7, 2016 at 2:18
  • @atk - So can an attacker brute force through the webservice. A 4 digit PIN is 10000 requests of 1KB (10MB upload). As for the hash function in the current time I'm afraid of trying anything from the blowfish family because of sweet32. argon2 would not be available on a MES system (those things are often not up to date with scripting languages) so scrypt may be the right thing, updated.
    – grochmal
    Commented Sep 7, 2016 at 2:36
  • @grochmai you don't use hashing to protect against an online brute force attack. You use them to protect against offli e attacks - when the hashes in the database have been exposed and possibly downloaded by the attacker. sweet32 does not magically make blowfish unsafe. It is (and was) unsafe if you encrypt too much with the same key. I do not believe bcrypt is affected.
    – atk
    Commented Sep 7, 2016 at 5:14
  • @atk - I was being stupid assuming that the PIN could be the only authentication option OP could use. I did a huge revamp of the answer: added a PBKDF2 key generation and then encryption of the PIN under it. I believe it is much better an option, but I'd really like your opinion on it.
    – grochmal
    Commented Sep 8, 2016 at 0:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .