Designing a System That Meets Document Security Requirements: Access Control, Watermarks, and Audit Logs

"Please make sure internal materials do not get out."

Security requirements usually arrive in this form. The direction is clear, but this alone does not determine what has to be built.

If you take the request at face value and set the goal as "a system that completely prevents leaks," the project becomes difficult. The reason is that you cannot stop someone from photographing what is shown on a screen with another device. If you start without acknowledging this, the acceptance phase turns into an argument along the lines of "you said it would be blocked completely."

The realistic goal is different: reduce the number of leak paths, raise the cost of the paths that remain, and make incidents traceable when they happen. This article describes how to turn document security requirements into a system design from that perspective.


1. Break down what to block by leak path

"Leak prevention" is not a single feature but a combination of several controls. Design becomes possible only after the paths are separated.

Each path needs a different control

Leak path Control Completeness
Viewing by unauthorized users Authentication and authorization, access control High
Taking a file out after download Download restrictions, view-only viewer Medium
Taking printouts out Print control, watermark Medium
Screen capture Capture blocking (limited), watermark Low
Photographing with another device Watermark Cannot be blocked; tracing only
Transcribing or memorizing the content None Cannot be controlled

The further down the table you go, the harder blocking becomes. The core of the design is to block the upper paths reliably and to leave a means of tracing for the lower ones.

State completeness in the requirements

It is a good idea to review this table together with the client and agree on what will be done, and how far, for each path. That agreement later becomes the acceptance criteria.

"Screen capture blocking" needs particular care. Whether it is possible depends on the operating system and browser environment, and workarounds exist. Unless the feasible scope is written down clearly, expectations and results will diverge.

Write what was agreed as statements that can be tested. Below are examples of how to rephrase requests.

Request received Statement that can be accepted against
People without permission must not see it When an account without permission requests the list, detail, file, thumbnail, or search results, every request is denied and the denial is recorded
Block downloads For confidential-grade documents, no path returns a response that downloads the original file. Viewing is provided only as images converted by the server
Block capture In the dedicated viewer (on the designated operating systems), the capture exclusion feature provided by the operating system is applied. Web browsers and photography with external devices are not subject to blocking and are traced by watermark
Make it possible to find the source if something leaks The identification code on the screen or printout can be used to look up the viewer, the date and time, and the document. The scope of handling for cases where only part of the code is visible is defined separately

Classify the documents by grade

Applying the same controls to every document paralyzes work. It is more realistic to define grades and set the level of control for each.

  • Public — no controls
  • Internal — viewable only by logged-in employees
  • Restricted — viewable only by designated departments and positions; downloads restricted
  • Confidential — individual approval required, view-only, watermark, full history recorded

You also need to decide who assigns the grade and by what procedure. Options include having the author designate it, applying a default grade per department, or applying it automatically when a document is saved to a particular location.

Grade change history must also be recorded. An approval procedure is often put in place so that lowering the grade of a confidential document does not become a path for taking it out.


2. Design the permission model

Access control is the area where blocking is most reliable. If there is a gap here, the remaining controls are meaningless.

Combine role-based and document-based control

Approach How it works Pros and cons
Role-based Permissions granted by position and department Simple to manage. Exceptions are hard to handle
Document-based Viewers designated per document Precise. Heavy management burden
Hybrid Roles by default, individual designation when needed Realistic in most cases

What has to be decided in the hybrid approach is whether an individual designation can exceed role permissions. You must decide whether to allow someone who normally has no permission to view a specific document, and conversely whether to exclude a specific document from someone who does have permission.

In terms of access control models, the distinction in the table is the difference between role-based (RBAC) and attribute-based (ABAC) access control. NIST defines ABAC as a method that decides whether to permit a request by evaluating the attributes of the subject, the object, the requested operation, and in some cases the environment conditions against policy, and describes RBAC as a special case of it that uses a single attribute, the "role."(NIST SP 800-162)

Most document security requirements cannot be expressed with roles alone. Conditions such as "confidential grade only on the internal network," "only during the project period," or "only if recently re-authenticated" can be decided only by looking at the document grade (an object attribute) together with the access location and time (environment conditions). The resulting structure sets the broad scope by role and narrows it by grade and environment conditions. There is no need to introduce a general-purpose policy engine from the start, but the attributes used in the decision must be fixed as a list. Which system each attribute comes from (HR data, document metadata, access information) and how current its value is determine the accuracy of the decision.

Fix the decision order in one place

Defects in the hybrid approach usually surface when rules conflict. If which side wins is implemented differently from screen to screen, for example when a role allows access but the document excludes the user, or when an individual grant exists but has expired, gaps appear. Define the order, put it in a single function, and make every access path go through that function.

Below is an example showing the decision order (TypeScript; the 5-minute re-authentication window is an example value). Attribute lookup is finished by the caller, and this function only makes the decision.

type Grade = 'PUBLIC' | 'INTERNAL' | 'RESTRICTED' | 'CONFIDENTIAL';
type Action = 'VIEW' | 'DOWNLOAD' | 'PRINT';
type DenyReason =
  | 'ACCOUNT_INACTIVE' | 'EXPLICIT_DENY' | 'NO_MATCHING_RULE'
  | 'ACTION_NOT_ALLOWED_FOR_GRADE' | 'REAUTH_REQUIRED';
type Decision = { allowed: true } | { allowed: false; reason: DenyReason };

interface AccessRequest {
  isAccountActive: boolean;
  action: Action;
  grade: Grade;
  isExplicitlyDenied: boolean;             // per-document exclusion
  individualGrantExpiresAt: number | null; // expiry time of the individual grant (epoch seconds)
  isAllowedByRole: boolean;                // whether a role/department rule matches
  lastAuthenticatedAt: number;             // time of last authentication (epoch seconds)
  now: number;
}

const REAUTH_WINDOW_SECONDS = 300;

function deny(reason: DenyReason): Decision {
  return { allowed: false, reason };
}

export function decideAccess(request: AccessRequest): Decision {
  if (!request.isAccountActive) return deny('ACCOUNT_INACTIVE');
  if (request.isExplicitlyDenied) return deny('EXPLICIT_DENY');

  const hasValidGrant =
    request.individualGrantExpiresAt !== null &&
    request.individualGrantExpiresAt > request.now;
  const isPublic = request.grade === 'PUBLIC';
  if (!isPublic && !request.isAllowedByRole && !hasValidGrant) {
    return deny('NO_MATCHING_RULE');
  }

  if (request.grade !== 'CONFIDENTIAL') return { allowed: true };
  if (request.action !== 'VIEW') return deny('ACTION_NOT_ALLOWED_FOR_GRADE');
  const isRecentlyAuthenticated =
    request.now - request.lastAuthenticatedAt <= REAUTH_WINDOW_SECONDS;
  return isRecentlyAuthenticated ? { allowed: true } : deny('REAUTH_REQUIRED');
}

There are four things to keep in this structure.

  • Deny when no rule matches. When a new grade or a new action is added, access does not open even if a rule is missed.
  • Exclusion comes before allowance. If the order is reversed, a single individual grant defeats the exclusion.
  • Compare expiry at decision time. If you rely only on a batch job to delete expired permissions, the permissions stay alive while the batch is stopped.
  • Return the deny reason as a value. This value becomes the failure reason in the audit log and the basis for telling the user why they were blocked. However, the wording shown on screen is defined separately from the reason value, so that a user without permission is not told whether the document exists.

Manage the permission lifecycle

With permissions, revocation is missed more often than granting.

  • Are permissions on the previous department's documents retained after a department transfer?
  • Is access blocked immediately on resignation?
  • Do temporary permissions expire after the project ends?
  • Do external partner accounts have a validity period?

It is safe to make an expiry date mandatory for temporary permissions. Permissions granted without expiry are never revoked by anyone and keep accumulating.

A procedure for reviewing permission status periodically is also needed: extract a list of who can currently access which documents and have an administrator review it.

If the document system holds personal information and therefore qualifies as a personal information processing system, this part is an obligation, not a recommendation. Article 5 of the Standards for Ensuring the Safety of Personal Information (개인정보의 안전성 확보조치 기준) requires that access rights be granted differentially within the minimum scope necessary to perform the work, that rights be changed or cancelled without delay when the person in charge or the work changes, and that records of granting, changing, and cancelling rights be kept for at least 3 years.(Standards for Ensuring the Safety of Personal Information) This is why the permission change history table must be kept separate from access records and given its own retention period.

One technical cause of delayed revocation is also worth noting. If permission decision results or user attributes are held in sessions, tokens, or caches, access continues until the cache expires even after the resignation has been processed in the HR system. For confidential-grade decisions, either do not use a cache or build a path that immediately invalidates the user's sessions and caches when permissions change.

Match the authentication method to the grade

Requiring additional authentication for confidential-grade documents is a common configuration.

  • Authenticate once more at the time of viewing
  • Apply multi-factor authentication
  • Restrict access location and device
  • Restrict access outside working hours

When you impose restrictions, you must build an exception handling path along with them. Cases where access is needed during a business trip or in an emergency will certainly arise. With an exception approval procedure and its records, work remains possible while control is maintained.

Separate download from viewing

The moment you let a file be downloaded, you lose control over that file. A file stored on a user's device can be moved anywhere.

To keep control, you need a path for viewing without downloading.

Approach How it works Notes
Server-rendered viewer Converted to images on the server and displayed The original is not sent down. Conversion load
Web viewer Displayed in the browser while blocking access to the original The original can be exposed depending on the implementation
Dedicated application Viewable only with a designated program Installation burden. Many control options

There is a point to watch when using a web viewer. To display a document in the browser, the data is delivered to the client in one form or another. If the structure allows the original to be extracted through developer tools or network records, there is no control.

Converting to images on the server and sending those down is free of this problem. The drawback is that text selection and search become impossible, but it is an appropriate trade-off for confidential-grade documents.

Where downloads must be allowed, conditions such as a limit on the number of downloads, a validity period, and entry of a reason are used. This is not complete control, but it reduces indiscriminate removal.

Verify on the server

This is obvious, yet it is a part that often goes wrong in practice.

  • Hiding a button on the screen is not control
  • A structure in which the list query filters documents but the detail query needs only an identifier is common
  • The file download path is sometimes left open separately
  • Preview images and thumbnails sometimes do not go through a permission check

The same permission check must be performed on every access path. In particular, if the URL of the file itself is exposed, the permission check can be bypassed, so the design must not leave any directly accessible path.

Sign file URLs and make them expire

Having the application server stream files directly keeps the permission check simple, but the load on the server is heavy for large files. A common configuration is therefore to let the storage or a dedicated file path respond directly, while the application checks permission and then issues a signed URL that is valid only for a short time.

The principle is to bind the document, the user, and the expiry time together, sign them with a key that only the server knows, and check the signature and expiry again when a request arrives. Below is an example for implementing this yourself (Node.js 16 or later, node:crypto).

import { createHmac, timingSafeEqual } from 'node:crypto';

interface DownloadClaim {
  documentId: string;
  userId: string;
  expiresAt: number; // epoch seconds
}

function sign(claim: DownloadClaim, secret: string): string {
  const payload = JSON.stringify([claim.documentId, claim.userId, claim.expiresAt]);
  return createHmac('sha256', secret).update(payload).digest('base64url');
}

export function createDownloadPath(claim: DownloadClaim, secret: string): string {
  const query = new URLSearchParams({
    u: claim.userId,
    e: String(claim.expiresAt),
    s: sign(claim, secret),
  });
  return `/api/documents/${encodeURIComponent(claim.documentId)}/file?${query}`;
}

interface VerifyInput {
  claim: DownloadClaim; // values read again from the request path and query
  signature: string;
  secret: string;
  now: number;
}

export function isValidDownloadRequest(input: VerifyInput): boolean {
  const { claim, signature, secret, now } = input;
  if (!Number.isInteger(claim.expiresAt) || claim.expiresAt <= now) return false;
  const expected = Buffer.from(sign(claim, secret));
  const given = Buffer.from(signature);
  return expected.length === given.length && timingSafeEqual(expected, given);
}

The nature is the same when you use the signed URL feature of a cloud storage service. AWS describes an S3 presigned URL as "a bearer token that grants access to those who possess it" and notes that it can be used multiple times until it expires.(Amazon S3 User Guide) A signed URL does not replace the permission check; it is a token that carries the result of a permission check around for a short time. The following are therefore designed together with it.

  • Keep expiry short, in minutes. The moment a URL is pasted into a messenger, it passes to someone else. The longer the expiry, the later a permission revocation takes effect. For S3, the same document describes how to deny requests made a certain time after signing with a bucket policy (the s3:signatureAge condition) and how to restrict the networks from which access is possible.
  • Expiry is checked only when the request starts. According to the same document, S3 checks expiry at the time of the HTTP request, so a download started just before expiry continues after expiry. The expiry time must not be written in the requirements as "the time after which the file is no longer transferred."
  • Include the user in the signature, and on paths that have a session, compare it with the session user. In a configuration where the storage responds directly, the comparison is not possible, so set the expiry even shorter.
  • Write an audit log entry at the time of issue. When the storage responds directly, the application cannot know about the actual download. Make it possible to link the issue records and the storage access logs by document identifier.
  • Do not use them for the confidential grade. For a grade that has no path at all through which the original is sent down, signed URLs are not issued either.
  • Make the signing key replaceable. If a key identifier is included in the URL, URLs issued with the previous key can be verified until their expiry time while the key is being rotated.

Common errors in permission design

Symptom Cause Fix
A document not in the list opens when its address is entered directly Only the list query has the permission condition; the detail and file APIs check only the identifier Put the decision function in a common layer and make every API that returns documents go through it. Include automated tests that call each API with an unauthorized account as a deployment condition
The body is blocked, but the title and part of the body appear in search results The search index was built without permission information Put grade and permission attributes in the index so results are filtered at the search stage, and decide again before returning results
Thumbnail and preview images open without login Conversion outputs are stored on a public path or CDN Treat conversion outputs at the same grade as the original and serve them through the same decision
Viewing works for a while with a resigned employee's account Permissions and attributes are kept in sessions or caches with no invalidation path Invalidate sessions and caches immediately when permissions change; decide on every request for higher grades
The previous user's document is visible via the back button or on a shared PC Document responses are cached by the browser or an intermediate server Apply Cache-Control: no-store to document and image responses
A temporary permission still works after its expiry date Expiry handling relies only on a deletion batch Compare the expiry time at decision time
Every document opens in the administrator screen Administrative functions do not go through the decision function Separate system administration permission from document viewing permission, and make administrator viewing go through the same decision and recording

3. A watermark is a means of tracing, not blocking

Expectations of watermarks often diverge from their actual effect.

What you can expect

A watermark overlays viewer information on the screen or printout. Two effects can be expected.

  1. Deterrence — leaking a document stamped with your own name is uncomfortable
  2. Traceability — if leaked material is found, you can identify whose viewing it came from

It has no blocking effect. Photographing and capturing remain possible even with a watermark. This must be made clear at the requirements stage.

Decide what to display

Tracing accuracy depends on what is put in the watermark.

  • Viewer name and affiliation
  • Employee number or account identifier
  • Date and time of viewing
  • Access IP or device information
  • Document identifier

The more information you include, the easier tracing becomes, but readability suffers. In practice, the approach is to display the minimum on screen and keep the details as server records: show only a short identification code on the screen and look up the viewing record with that code.

There are three things to decide when using an identification code.

  • Unit of the code — if a new code is issued for each viewing, it narrows down "who, when, and which document" in one step. A fixed code per user is easy to implement, but the date and time and the document have to be found from other clues.
  • How the code is generated — a random value issued by the server is better than a value derived directly from the employee number or account name. Personal information is not carried directly on leaked material, and nobody can guess another person's code from looking at a code.
  • Retention period of the code and the records — if the viewing records to be looked up by the code are deleted first, the watermark becomes an unreadable mark. Align the period during which watermark tracing must be possible with the audit log retention period.

Decide how to display it

  • Position — fixed, or moving at regular intervals. Moving makes it harder to capture with a specific part covered
  • Opacity — a level at which the document can be read while the mark remains identifiable when photographed
  • Density — repeated across the whole screen, or shown only in part
  • Application when printing — whether to apply it to the screen and to printouts respectively

Printout watermarks must be designed separately. Screen watermarks are handled in the browser, but printing is handled at the output stage, so a different method is needed. Generating a file with the watermark inserted on the server at print time and sending that down is the reliable approach. The density must also be set separately from the screen. In the watermark DRM solution we built, there was also the problem that a dark mark made the document hard to read while a light one disappeared in the copying process, so we had to adjust density and placement to find a balance.

You also need to decide where the screen watermark is composited. Having the browser draw it as a separate element over the document is simple to implement, but because the watermark and the document exist separately on the user's device, turning the mark off is not difficult. For higher-grade documents, the server draws the watermark in when it converts pages to images, so that screen data without a watermark is never delivered to the client. In this case the image differs for each viewer, so conversion results cannot be shared in a cache across users, and the conversion load must be reflected in capacity sizing accordingly.

Cases where a watermark does not hold up

A watermark is a means of tracing only when it remains on the leaked material and can be read. Work through the following situations in advance at the design stage.

Situation Result What the design can do
A capture or photo of only part of the screen Only an area without the watermark may leak Repeat it across the whole screen, with spacing designed so that the full code appears at least once wherever a screen is cropped
Low-resolution photography, downscaling, recompression A faint watermark is smeared and unreadable Run readability tests under actual photography and downscaling conditions and set the density and font size from the results
Retyping or summarizing the content and passing it on The watermark does not follow No technical means. Narrowing the scope with viewing records is the limit
The same document viewed by several people For leaked material without a watermark, every viewer is a candidate Narrowing who can view is the way to narrow the scope of tracing

The second item is worth including as an acceptance item. If you only confirm that "the watermark is displayed" and move on, you find out whether the code can actually be read from a photo only after an incident. Running one test in which the code is read from a photo taken of the target monitor with an ordinary smartphone is enough.

Marks can also be embedded in the document itself

Separately from visual watermarks, there is a method of inserting identification information into the document file itself. It is not visible to the naked eye but can be confirmed through analysis.

Points to review when applying this method:

  • Can it be applied to each file format?
  • Does it survive editing and re-saving?
  • What tool can be used to check it?
  • Has leaving personal information in the file been reviewed?

The last item is important. Identification information remaining in the file means that when the file goes outside, personal information goes with it. What information to include must be decided carefully. Here too, inserting an identification code issued by the server instead of a name or employee number is the safe approach.

An invisible mark cannot replace a visible watermark, because their roles differ.

Category Visible watermark Invisible mark
Deterrence Yes. The viewer is aware of the mark No. There is no deterrence unless its existence is made known
How it is checked By eye A dedicated detection tool and the original or a key
Weak point Cropping, covering Whether it survives format conversion, re-saving, and photography differs by method
Suitable use Screen viewing, printouts Verifying the origin of documents taken out as files

Whether an invisible mark can still be detected after conversion, printing, or photography varies greatly by method and product, and the conditions presented by the vendor can differ from actual usage conditions. If you are considering adoption, define the target file formats and the expected leak paths and run detection tests yourself, and record the paths where the mark is not detected under the limitations item of the requirements document. If you plan to use detection results as grounds for disciplinary action or legal proceedings, the possibility of false detection and the method of recording the detection procedure are also subject to review.


4. Design the audit log

If there are no records to check when a leak occurs, the controls described above lose their meaning.

First check the level required by law

For a system that handles personal information, requirements on access records apply. The content of Article 8 of the current Standards for Ensuring the Safety of Personal Information (Personal Information Protection Commission (개인정보보호위원회) Notice No. 2025-9, partially amended October 31, 2025) is as follows.(Standards for Ensuring the Safety of Personal Information)

Provision Content
Article 8(1) Keep and manage the access records of persons who accessed the personal information processing system (excluding data subjects) for at least 1 year
Article 8(1), proviso At least 2 years if any of the following applies: a system that processes personal information on 50,000 or more data subjects, a system that processes unique identification information or sensitive information, or a facilities-based telecommunications business operator (기간통신사업자)
Article 8(2) Define in the internal management plan, and carry out, the cycle and method for checking and inspecting access records and the status of personal information downloads, and the follow-up action procedure
Article 8(3) Measures to keep access records safely so that they are not forged, altered, stolen, or lost

Article 2 of the same Notice defines access records as an electronic record of the identifier, the date and time of access, access location information, information on the data subjects processed, the work performed, and so on. Applied to a document system, the scope of recording covers who, when, from where, a document containing whose information, and whether it was viewed or downloaded.

Pay attention to the effective date. The Addenda to Notice No. 2025-9 provide that the amended provisions of Article 8(1) and (2), Article 5(1) and (6), and others take effect one year after the date of issuance, that is, from October 31, 2026. There are two differences from the previous provisions (Notice No. 2023-6) that apply until then.

  • Scope of retention — previously it was the access records of "personal information handlers," but the amended provisions broadened it to "persons who accessed the personal information processing system (excluding data subjects)." You need to check that the records of those who are not internal employees, such as partner company accounts, are not missing.
  • Inspection cycle — previously access records had to be inspected at least once a month, but the amended provisions changed this so that the cycle and method are defined in the internal management plan. Rather than a fixed feature such as a "monthly inspection report," the system needs a feature that extracts the inspection targets according to the defined cycle and records the inspection results and follow-up actions.

The retention period is a lower bound. On the other hand, viewing records are themselves the personal information of employees, so accumulating them indefinitely without grounds is not appropriate either. Define the retention periods for access records (at least 1 or 2 years) and for permission change records (Article 5(3), at least 3 years) separately, and design the procedure for deleting records past their period along with them.

For the interpretation of the provisions and application cases, you can refer to the guide published by the Personal Information Protection Commission. However, the guide at the link below is the October 2024 edition and is based on the content before the Notice No. 2025-9 amendment, so for the amended provisions the text of the Notice must be checked first.(Guide to the Standards for Ensuring the Safety of Personal Information)

The scope of application and the specific requirements vary depending on the type and scale of the personal information processed. Whether the document system qualifies as a personal information processing system has to be determined first, and when applying this to an actual system, please check the text of the laws and regulations and the latest guidance from the competent authority.

Decide what to record

These are the items that should be recorded from a document security perspective.

Category Items
Subject Account identifier, affiliation, access IP, device information
Object Document identifier, document grade, document name
Action View, download, print, share, permission change, grade change
Time Request time, processing completion time
Result Success or failure, failure reason

Failure records are especially important. Repeated attempts at unauthorized access are a signal that must be detected. If only successes are recorded, this signal is missed.

Things to decide together when defining the items:

  • Record the values as they were at the time. For values that change later, such as document grade and affiliation, copy the value at the time instead of a reference. Otherwise, if you look it up after the grade has been lowered, the fact that "a confidential document was viewed" disappears from the record.
  • Do not put document content in the log. If search terms, parts of the document body, or entire request bodies are recorded as they are, the audit log becomes another leak path. Record only identifiers and actions, and check the content in the source system.
  • Define the behavior on recording failure by grade. When the log store fails, you have to decide whether to block or allow viewing. One way to divide it: for the confidential grade, viewing is not allowed if it cannot be recorded, and for the grades below it, entries are stored temporarily and resent. If this is not decided, behavior chosen arbitrarily by the implementer goes into production.
  • Stamp the time in one place, on the server. If you use the time sent by the client or clocks that differ from server to server, the sequence cannot be reconstructed in an incident investigation. Include server time synchronization in the operational items.

Protect the log

If the audit log itself is tampered with, it is meaningless.

  • Separate the party that records from the party that manages
  • Make sure ordinary operators cannot modify or delete logs
  • Keep them in separate storage
  • Provide a means of integrity verification

The actions of administrator accounts are also subject to recording. If anything, the more privileged the account, the more important the record.

Detect tampering with a hash chain

One way to make "a means of integrity verification" concrete is a hash chain. When computing the hash of each record, the hash of the record immediately before it is included in the input. If a row in the middle is modified or deleted, the links after it no longer match, so the tampered position can be found simply by recomputing the whole chain.

Below is an example that assumes PostgreSQL 11 or later (it uses the built-in sha256 function and the EXECUTE FUNCTION syntax). The sequence number, time, and hashes are filled in by the trigger, not by the application.

CREATE TABLE audit_log (
  seq            bigint PRIMARY KEY,
  occurred_at    timestamptz NOT NULL,
  actor_id       text NOT NULL,
  client_ip      inet,
  action         text NOT NULL CHECK (action IN
                   ('VIEW','DOWNLOAD','PRINT','SHARE','GRANT_CHANGE','GRADE_CHANGE')),
  document_id    text NOT NULL,
  document_grade text NOT NULL,
  result         text NOT NULL CHECK (result IN ('ALLOWED','DENIED')),
  deny_reason    text,
  prev_hash      bytea NOT NULL,
  row_hash       bytea NOT NULL
);

-- Build the hash input in a fixed format that does not depend on session settings (time zone, etc.)
CREATE FUNCTION audit_payload(r audit_log) RETURNS text
LANGUAGE sql STABLE AS $$
  SELECT jsonb_build_array(
    r.seq,
    to_char(r.occurred_at AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.US'),
    r.actor_id, host(r.client_ip), r.action, r.document_id,
    r.document_grade, r.result, r.deny_reason
  )::text;
$$;

CREATE FUNCTION audit_log_chain() RETURNS trigger
LANGUAGE plpgsql AS $$
DECLARE
  last_row audit_log;
BEGIN
  -- Serialize so that records arriving concurrently do not point to the same previous row
  PERFORM pg_advisory_xact_lock(hashtext('audit_log_chain'));
  SELECT * INTO last_row FROM audit_log ORDER BY seq DESC LIMIT 1;

  NEW.seq         := COALESCE(last_row.seq, 0) + 1;
  NEW.occurred_at := clock_timestamp();
  NEW.prev_hash   := COALESCE(last_row.row_hash, sha256(''::bytea));
  NEW.row_hash    := sha256(NEW.prev_hash || convert_to(audit_payload(NEW), 'UTF8'));
  RETURN NEW;
END;
$$;

CREATE TRIGGER audit_log_chain_before_insert
BEFORE INSERT ON audit_log
FOR EACH ROW EXECUTE FUNCTION audit_log_chain();

-- Allow only insert and select for the application account (app_user is an example name)
REVOKE ALL ON audit_log FROM PUBLIC;
GRANT INSERT, SELECT ON audit_log TO app_user;

Verification is done with a single query that recomputes the hash of every row and checks that the sequence numbers and the links to the previous and next rows are correct. Zero rows means everything is normal; if rows are returned, check from that sequence number.

SELECT seq
FROM (
  SELECT a.seq, a.prev_hash, a.row_hash,
         lag(a.seq)      OVER (ORDER BY a.seq) AS previous_seq,
         lag(a.row_hash) OVER (ORDER BY a.seq) AS previous_hash,
         sha256(a.prev_hash || convert_to(audit_payload(a), 'UTF8')) AS recomputed
  FROM audit_log a
) checked
WHERE row_hash <> recomputed
   OR (previous_seq IS NOT NULL
       AND (seq <> previous_seq + 1 OR prev_hash <> previous_hash))
ORDER BY seq;

You need to know what this method does not guarantee before using it.

  • Within the same database, it only detects. The table owner and superusers are not affected by REVOKE, and if someone modifies a row and then recomputes and writes all the hashes after it, the chain matches again. Deleting the most recent rows outright is also not revealed by the chain alone.
  • So anchor the end value of the chain outside the database. At regular intervals, record the last sequence number and hash in storage that the database administrator cannot write to, and compare against that value when verifying. Storage that cannot be overwritten or deleted during the retention period once written suits this purpose. For example, Amazon S3 Object Lock stores objects in a WORM model, and in compliance mode even the root user of the account cannot overwrite or delete an object version during the retention period.(Amazon S3 User Guide) Technically, the "separation of the party that records from the party that manages" mentioned earlier is achieved at this point.
  • Recording order is serialized. The lock in the example makes records be written one at a time. In a system with a high viewing frequency this section can become a bottleneck, so consider a configuration in which records are put on a queue and a single writer appends them to the chain in order, or in which the chain is split into several branches. Throughput must be measured directly in the target environment to make the judgment.
  • Changing the hash input format breaks verification of past records. When adding a column, give the format a version so that earlier rows can be verified with the earlier format. This is also why the example converts the time to a fixed UTC format. If the string varies with the session time zone, verification fails even without tampering.
  • Deleting rows past their retention period cuts off the front of the chain. Keep the last hash of the deleted range in external storage and use that value as the starting point of the remaining chain for verification. This is also why the verification query does not separately check the prev_hash of the first row.

Common errors in audit logs

Symptom Cause Fix
In an incident investigation, "who viewed it" is available but "who attempted it" is not Requests denied by the permission check never reach the logging code Record at a single point that receives the result of the decision function (allowed or denied, and the reason)
File download records are fewer than actual downloads Only the screen APIs log; the file path and signed URL issuance do not List every path that sends documents out and check whether each one records
Every IP in the log is the same value The address of the proxy or load balancer is recorded Use only the client address passed on by a trusted proxy. Do not trust arbitrary request header values as they are
History queries become slow after a few months Everything accumulates in a single table and there is no index matching the query conditions Indexes matched to queries by document, by user, and by period; partitioning by period and a procedure for deleting records past the retention period
An operator cleans up the log table while responding to an outage The operations account has delete permission and the retention period exists only in a document Remove modify and delete permissions from the operations account; perform deletion only through a separate procedure that checks the retention period
Inspections are carried out but no evidence remains There is only a query screen and no feature for recording inspection results Also implement a feature that records the inspection date and time, the inspector, the scope checked, and the actions taken

It is a record only if it can be viewed

If records are only accumulated and there is no means of querying them, they cannot be used when an incident occurs.

  • Viewing history query by document
  • Access history query by user
  • Search by period and action type
  • Anomalous pattern query — more document views than usual, bulk downloads, access outside working hours

For anomalous patterns, it is better to set up alerts. Becoming aware at the time of occurrence leaves more room to respond than checking after the fact. However, if the thresholds are set loosely and alerts pour in every day, the person in charge soon stops checking. Set the thresholds relative to each user's usual usage, and keep them as configuration values so they can be adjusted during operation. The structure in which alerts get ignored is covered separately in The Point Where Notifications Start Getting Ignored — Designing a Delivery System.


5. Build a path for cases where documents must be taken out

Strengthening controls alone blocks legitimate work as well. Situations where materials must be provided externally do exist.

  • Submission to supervisory authorities
  • Handing over deliverables to a contract counterparty
  • Providing materials for legal advice
  • Responding to audits

An official export procedure is needed for such cases.

Item What to define
Request Who requests it, and with what form
Approval Approvers by grade
Processing Watermark application, validity period, password setting
Record Reason for export, recipients, list of documents
Follow-up Confirmation of return or destruction

If the procedure is too heavy, people send things by personal email or messenger. Minimizing the approval steps and processing requests quickly actually helps maintain control.

Setting a validity period on files that go outside is another approach that is used: the file is configured not to open after a certain period. It is not complete, but it reduces the situation where old materials keep circulating.


6. Reconcile the points that conflict with work

Security controls inevitably conflict with convenience at work. If this reconciliation is not done at the design stage, the controls come undone during operation.

Excessive control creates workarounds

These are commonly observed.

  • Downloads are blocked, so people capture the screen and share it
  • Sending external email is blocked, so people send through personal messengers
  • Approval is required every time, so people obtain files in bulk in advance and use them
  • Access is inconvenient, so people keep copies in personal storage

When controls get in the way of work too much, people look for workarounds. And a workaround is a path with neither control nor records. As a result, the level of security drops further.

Consider partners and external users

A system used only by internal employees is actually the simple case. Once there are external users, the design changes.

  • Account issuance and revocation procedures
  • Limiting the scope of access by affiliated organization
  • Blocking everything at once when the contract ends
  • The level of control to apply to external users

For external users, it is common to apply stronger controls while keeping the scope narrow: designate only the documents they need to view, and restrict downloads in principle.

Prepare an exception procedure

Situations where controls must be relaxed will certainly arise.

  • Who can approve it?
  • How long is it valid?
  • What records are kept?
  • Is it reviewed afterwards?

A design that allows no exceptions is actually the dangerous one. Without an official exception path, an unofficial path appears, and it is not recorded.


7. Frequently asked questions

Can screen capture be blocked completely?

No. Depending on the environment, it can be made partially difficult.

  • With a dedicated application, there are cases where operating-system-level capture restriction features can be used
  • In a web browser environment, restriction is difficult
  • Using a virtual desktop environment increases the number of control points

The scope of the features provided by operating systems is stated in the official documentation, and so are their limits.

Environment Feature Scope and limits stated in the official documentation
Android app Set FLAG_SECURE on the window Screenshots come out as a blank screen, and the window is not shown on non-secure displays (such as screen casting). On Android 11 (API 30) and lower, it is noted that it may not work reliably depending on the device
Windows desktop app SetWindowDisplayAffinity WDA_MONITOR blanks the window content on paths other than the monitor, and WDA_EXCLUDEFROMCAPTURE (Windows 10 version 2004 or later) excludes the window itself from capture. It is explicitly stated that this is not a security feature or DRM and that protection is not guaranteed in cases such as photographing the screen

The sources are the Android developer documentation and Microsoft Learn, respectively. Both features are something an app requests from the operating system for its own window, so they can be used only when building a dedicated application and cannot be applied to web pages opened in a browser. If capture blocking goes into the requirements, write the "supported operating systems and versions, and the capture paths covered" as a table, and decide whether viewing itself is to be allowed in other environments.

Whatever the method, photographing the screen with another device cannot be prevented. So when you accept capture blocking as a requirement, the applicable environments and the limits must be stated in the document.

Can security features alone be added to an existing document system?

It depends on the structure of the existing system. Points to check:

  • Is document access through a single path, or are there several paths?
  • Are files stored in a directly accessible location?
  • Can the existing permission scheme be extended?
  • Are there points available at which logs can be written?

If files are in a directly accessible location, that has to be cleaned up first. However much you control the screens, someone who knows the file path can bypass them.

Does applying encryption solve it?

Encryption is necessary but not sufficient. The problems it solves and the ones it does not are different.

  • Solved — theft of storage media, eavesdropping in transit, leakage of backup files
  • Not solved — a user with legitimate permission taking out the decrypted content

A large share of document leaks are the second case. Apply encryption as a baseline, but permission management and a means of tracing must be in place alongside it.

How far is it appropriate to implement?

It is decided by the sensitivity of the documents and the scale of damage if they leak. The criteria for judgment:

  1. What damage occurs if it leaks?
  2. Which paths are currently open?
  3. What are the adoption cost and work impact of each control?

Applying the highest level to every document is inefficient. Dividing documents into grades and concentrating on the higher grades is more cost-effective. In most cases, the documents that actually qualify as confidential are a fraction of the total.


8. Checklist before starting

Requirements definition

  • Have the control and completeness for each leak path been agreed?
  • Are the areas that cannot be blocked stated in the document?
  • Are the document grade scheme and the level of control per grade defined?
  • Is there a party that assigns grades and a procedure for changing them?

Permission design

  • Is the relationship between role-based permissions and individual designation defined?
  • Do temporary permissions have an expiry date?
  • Is there a procedure for revoking permissions on department transfer and resignation?
  • Is there a periodic permission review procedure?
  • Is server-side permission verification performed on every access path?
  • Is there no path that allows direct access to files?
  • Are the decision order for conflicting rules and the "deny when no rule matches" principle implemented in one place?
  • Do search results, thumbnails, and conversion outputs go through the same decision?
  • Are permission changes reflected in sessions and caches immediately?
  • Are the expiry time of signed URLs and the method of recording their issuance defined?
  • Is the retention period for records of granting, changing, and cancelling permissions defined?

Watermark

  • Are the displayed content and the display method defined?
  • Is the handling of printouts designed separately?
  • If file embedding is used, has it been reviewed from a personal information perspective?
  • Is the watermark for higher-grade documents composited on the server?
  • Has a test been run to read the identification code from photographed and downscaled images?
  • Does the retention period of the viewing records looked up by identification code match the period for which tracing is needed?

Audit log

  • Has the retention period under the applicable laws and regulations been checked?
  • Have the effective date of the amended Notice and the scope of access record retention (whether it includes those who are not internal employees) been checked?
  • Are failed access attempts recorded?
  • Are administrator actions also subject to recording?
  • Are there measures to prevent log tampering?
  • Is the reference value used for integrity verification kept somewhere the database administrator cannot modify?
  • Is the behavior on log storage failure defined by grade?
  • Is there a procedure for deleting records past the retention period?
  • Is there a means of querying history by document and by user?
  • Are there alert thresholds for anomalous patterns?

Operations

  • Are the exception approval procedure and the method of recording defined?
  • Is the level of control for external users defined separately?
  • Has the impact of the controls on work been reviewed?

Closing

The most important thing in document security design is making clear at the outset what can and cannot be done.

Permission control can block reliably. Downloading and printing can be controlled to a considerable extent. Screen capture is limited depending on the environment. Photographing with another device cannot be prevented; it can only be traced.

If this distinction is agreed at the requirements stage, the subsequent design becomes the work of deciding which controls to apply to each path and to what extent. Conversely, if "complete blocking" is set as the goal, an argument that cannot be settled remains at the acceptance stage.

We have built a watermark DRM solution that combines document permission management with printout watermarks and applied it to an environment of 3,000 cumulative users. If you need a review at the stage of turning document security requirements into a system, please contact us.


References