Skip to Content

I remember one case where we did a threat modeling workshop for a product that consists of a rich client that allows editing of objects (e.g. contract, a file, a master data record, source code …). These objects are managed by the server and the server keeps track of all these changes and maintains the appropriate version history. To keep track of the changes each object gets a temporary unique identifier, which is assigned to the object in scope. With the identifier the server can verify and manage versioning.

From a pure functional view point any unique identifier serves the purpose. But in threat modeling we are not thinking in proper working solutions but we want to know how we can break things. Let’s switch the perspective from a developer to a hacker. Where the developer might think uniqueness is key and helps to achieve the objective of consistent versioning, the hacker in us thinks: Hey, there is an identifier, what can I do with it to do something unexpected?

It is easy to observe identifiers if you have access to the system as a normal business user. In our case we just need to touch a few objects in a row, it does not even matter if these objects hold sensitive information (let’s look at that later). It turned out that the identifiers are based on a sequence. The server just incremented the identifier by one with each request. As said, that is perfectly fine for the pure functional use case. But for the hacker in us it is an interesting hook. A sequence gives at one hand a clear view on the history of identifiers and allows on the other hand a simple prediction of upcoming identifiers.

Let’s look what happens if we change the identifier to an identifier that already has been used. How will the system behave in this case? It might be possible to overwrite an object that already was created. The same is true for an identifier yet to be used; you could change the identifier to the current value plus one to interfere with the work the next edit job is doing.

What can go wrong here? If the identifier is the sole barrier for consistency, an attacker can tamper with the records in the system. Depending on the object type this might allow anything between nuisance and criminal fraud.

On the basis of this abstract information we cannot conclude on that. In addition, we are not yet sure if the identifier in use is just an optimization, and tampering with the identifier is not working as the server does different other checks and will figure out that something is going wrong or simply will not allow any attempt to manipulate files or objects in that way.

But hey, we are in a threat modeling workshop, we do not start analyzing the server behavior ourselves, we just ask the developers in the room. And the question is as simple as that: What happens if an attacker is manipulating the identifier by incrementing it or using by using a past value?

And be sure, there will be silence for a moment, the developers will think about it. If they actually work on that for quite a while, you might get the answer fast. If the team is only responsible for the client, they might need to check with someone else or dive into that deeper later on.

But we found a potential vulnerability. Now all we need to do is to figure out how high the risk of the respective threat is and consider the need and cost of a mitigation.

Typically, I avoid discussing the mitigations in detail. But in this case there is a standard cure. Identifiers that have potential security relations (confidentiality, integrity…) should be based on cryptographically secure random numbers (be sure to use a secure random function). Having that in place, the chance of guessing or predicting and thus tampering with the identifier is basically gone.

What is my conclusion? Successful threat modeling requires a different perspective (how can I break it), curiosity (what can I do with that, even if it is not immediately an attractive hacking target), and then you just need to raise a few simple question – e.g. What happens if I increment the identifier manually on client side by one?

In my threat modeling workshop, the threat did not really materialize as the surrounding framework prohibited a feasible materialization of a successful attack. Is it worth attacking your identifiers? Let me know, happy to discuss your scenario with you.

To report this post you need to login first.

8 Comments

You must be Logged on to comment or reply to a post.

  1. Jens Schwendemann

    Hi Oliver,

    interesting read. Do you know by chance a CSPRNG (or the like) within ABAP that would allow me to create cryptographically secure identifiers?

    My use case is creating secure codes for a voucher. While we take measures that we only accept those we created ourselves, I’d from a IT professional point of view, would like to issue a more “random” code than e.g. FM “QF05_RANDOM” or class “CL_ABAP_RANDOM” or even ” CL_SYSTEM_UUID” would be able to create.

    Thanks and kind regards

    Jens

    (0) 
    1. Wolfgang Janzen

      If it’s just about secure random then ABAP function module GENERATE_SEC_RANDOM can be used. Examples: CL_HTTP_SERVER_NET=>CREATE_LOGIN_XSRF_TOKEN or CL_HTTP_SECURITY_SESSION=>_CREATE_XSRF_TOKEN.

      For a session identifier (SessionID) this is not sufficient, though – since “randomness” alone does not guarantee the required “uniqueness”. For (sole) “uniqueness” you can use UUIDs (e.g. CL_SYSTEM_UUID=>CREATE_UUID_X16). Combining both (by concatenating the XSTRINGs) will provide a “unique & random” number which can be used as session identifier. That’s done (in the kernel) to create the Security Session ID (CL_HTTP_SECURITY_SESSION=>_CREATE_SESSION_ID). It’s important to mention that this SessionID is only transmitted but not persisted; see explainations in method CL_HTTP_SECURITY_SESSION=>_CREATE_SESSION_ID (and kindly ignore wrong spellings there).

      (0) 
      1. Jens Schwendemann

        Hi Wolfgang,

        great insights, thank you very much.

        If i do understand correctly (I’m in no means a security expert) I would need some concatination of CL_SYSTEM_UUID=>CREATE_UUID_X16 and GENERATE_SEC_RANDOM.


        While CL_SYSTEM_UUID=>CREATE_UUID_X16 may suffice from a business perspective, it will not give full randomness, hence will allow a potential attacker (I know this is kinda constructed but let’s assume there is this high profile attacker just for the sake of an example by the book) to guess the remainder part of the UUID more easily.


        GENERATE_SEC_RANDOM will give me a secure random number, which isn’t unique.


        What I don’t understand is: Why would I not want to persist this concatenated UUID + random number? My understanding would be: I make up this string, persist it as a generated voucher ID and send it to the third party, that is responsible for managing all the vouchers. Please keep in mind, I don’t want to create such a complicated thing as a session management from scratch, only bring CL_SYSTEM_UUID=>CREATE_UUID_X16 up to snuff for my voucher ID requirement.


        Many thanks and kind regards

        Jens

        (0) 
        1. Wolfgang Janzen

          UUIDs are unique but also predictable – that’s what Oliver’s post is about.

          A random number is not predictable but not guaranteed to be unique.

          By concatenating a UUID and a random number you preserve both properties.

          Well, a Security Session ID is like a credential: you should not store it somewhere in plaintext. In order to validate a received SessionID it’s sufficient to perform the comparison on the hash values – like it’s done for passwords.

          For the ABAP Http Security Sessions:
          The ContextID (which is stored) is derived from the SessionID (which is transmitted) by applying a hash to the random number part of the SessionID, leaving the UUID part untouched and thus preserving the uniqueness property. The hash (MD5 is sufficient for that purpose) ensures that the operation cannot be inverted, i.e. it’s not possible to reconstruct the SessionID from a given ContextID.

          Frankly speaking I did not fully understood your use-case.
          Normally the server is creating the SessionID – and not the client (keyword: session fixation). The client simply needs to (temporarily) memorize the SessionID and present it in subsequent requests. Usually, session cookies are used for that purpose.

          BR Wolfgang

          (0) 
          1. Jens Schwendemann

            Thanks again for the detailed explanations.

            I also think we don’t talk about the same requirement / use case. I simply want to create “not so easy predictable” ID that I’d (simply speaking) print on a gift-card like an iTunes or amazon gift card you could get in a supermarket or gas station. But because we do not manage that whole “gift-card” / “voucher” processing ourselves, we are to transfer all created IDs to a third party. This happens completely asynchronous (thinking of PGP signed sFTP at the moment). So there’s no “user session” or whatsover in place here.

            Just me (maybe being paranoial) wanting to have some ID a little more secure than just old plain UUID. 😉

            Hope this makes sense. But again, thanks for the meaningful insights on session handling, was *really* fun & interesting to read about.

            Cheers

            Jens

            (0) 
            1. Wolfgang Janzen

              Thanks for the insight.

              Well, for vouchers / gift-cards you have indeed similiar requirements than for security session IDs: they should not be easy to guess and they need to be unique (since you have to ensure that they can only be used exactly once).

              But still: the system which is creating them should also be the one validating them. And you might also not want someone to be able to get a list of all vouchers… – that’s why you should not store the voucher itself but only a hashed version.

              The only difference is:
              A security session can be used multiple times – but a voucher should ensure a one-time usage. So, after successful validation of the voucher, you should mark it “consumed” (memorizing the timestamp and also a reference to the order – to be able to provide some reasoning why the voucher is no longer valid, in case the consumer is complaining). Amazon is doing that – you can always check when you have consumed which voucher and for what you’ve made use of it.

              Cheers,
              Wolfgang

              (0) 
              1. Jens Schwendemann

                Thanks again Wolfgang, sorry for the late reply.

                Ok, I think I understood in which direction your recommendation goes. This would yield into something like this:

                1. I combine a 16 Byte (32 Hex Char) UUIDe.g. from CL_SYSTEM_UUID=>CREATE_UUID_X16 and a 8 Byte (16 Hex Char) random number from GENERATE_SEC_RANDOM.

                Result from this would be 57730D67766D1690E10080000A060165 AA57D1164B9642DB

                2. I  apply a hash (e.g. SHA256) to the random part AA57D1164B9642DB.

                Result from this would be D46E63FB5EED6A8357297C17729376C9F163915164DEF8C3353B1CC102FF8589

                3. I store the unique part and the hashed random (the result from 2.)

                Result from this would be 57730D67766D1690E10080000A060165 D46E63FB5EED6A8357297C17729376C9F163915164DEF8C3353B1CC102FF8589

                4. I send out 57730D67766D1690E10080000A060165 AA57D1164B9642DB, this is my voucher ID

                5. When validating, I extract the random part of the given voucher ID (AA57D1164B9642DB) and apply the hash function to that part (D46E63FB5EED6A8357297C17729376C9F163915164DEF8C3353B1CC102FF8589). I also extract the unique part of the given voucher ID (57730D67766D1690E10080000A060165). I then combine the unique part and the then hashed random part

                Result would be 57730D67766D1690E10080000A060165 D46E63FB5EED6A8357297C17729376C9F163915164DEF8C3353B1CC102FF8589

                6. I compare this to my saved voucher data. If there’s a match I’ll do my stuff I’ll need to do when encashing a voucher and mark the voucher processed after that.

                That should pretty much wrap it up… However as this would give me great security and would be feasible if there would be no manual user interaction involved, it is not feasible if the user should have the option to encash the voucher by typing in the voucher ID into some webform. There’s of course a barcode scanning planned to deal with the majority of the voucher IDs, but manual entry should still be possible.

                So my questions go along this:

                1. Is my process laid out in steps 1-6 correct, from a technical point of view
                2. Do you have an idea how to come up with a 16 to 25 (at max!) length voucher ID without comprising too much security. Unfortunately, either CL_SYSTEM_UUID=>CREATE_UUID_X16 (32 Char) and GENERATE_SEC_RANDOM (16 Char) will generate lengthy outputs. Shortening  them by just clipping seems not like the wisest idea (guts feeling)

                Any further insights are really welcome. Thanks again so much for your time spent and the really great answers so far.

                Cheers

                Jens

                (0) 

Leave a Reply