wissel.net

Usability - Productivity - Business - The web - Singapore & Twins

Protecting sensitive information in Notes documents


Even in the most social businesses there is information that is available only on a "need to know" basis. Sometimes it is only a small subset of the fields in a document. In a Notes client, as long as I can see a document, I can see all the item values in it (using the document properties box), even if the field is hidden in the current form. So what are my options to protect a few sensitive fields?:
  1. Encrypt the fields with an encryption key that only the authorised user have. Problem here: you need to manage these keys and need a different set for each use case - messy. Also you can't show any of these fields in a view
  2. Hide the database design when applying the template. Looks good on the first view, but a semi skilled user can easily bypass that (e.g. copy & paste into an empty database, create a private view, use a @Prompt smart icon, use the free Document viewer or NotesPeek) - security by obscurity never works
  3. Store the sensitive data in a second document that is protected by reader names that are different (more restrictive) than the main document. This approach also keeps (given you have security set) curious admins out, a capability RDBMS is lacking
  4. Change the process and remove the need for the fine grained access control
Let's have a closer look at option 3. Notes allows to pull in values from a different document using @GetDocField. So once we have the secret document, we can pull in these values. If a user can't see that document no value is retrieved. The formula for such a computed for display field would look like this:
@If (RiskAssessmentID= "";@Return ( "n/a" ); "" );
tmp := @GetDocField (RiskAssessmentID; "RiskAssessment" );
@If ( @IsError (tmp ); "nothing to retrieve";tmp )
To create such a "secondary document" a few lines of LotusScript in a button make it a seamless experience:
Sub Click (Source As Button )
    Dim doc As NotesDocument
    Dim riskDoc As NotesDocument
    Dim uiDoc As NotesUIDocument
    Dim db As NotesDatabase
   
    Dim w As New NotesUIWorkspace
    Set uidoc = w. CurrentDocument
    Set doc = uidoc. Document
    If doc. IsNewNote Then
        Call doc. Save ( True, True )
    End If
    Set db = doc. ParentDatabase
    If doc. RiskAssessmentID ( 0 ) = "" Then
        Set riskDoc = db. CreateDocument
        Call riskDoc. ReplaceItemValue ( "Form", "RAF" )
    Else
        Set riskDoc = db. GetDocumentByUNID (doc. RiskAssessmentID ( 0 ) )
        If riskDoc Is Nothing Then
            Set riskDoc = db. CreateDocument
            Call riskDoc. ReplaceItemValue ( "Form", "RAF" )        
        End If
    End If
   
    Call riskDoc. MakeResponse (doc )
   
    If  w. DialogBox ( "RAF", True, True, False, False, False, False, "Please provide your Risk Assessment",riskDoc, True ) Then
        Call riskDoc. Save ( True, True )
        Call doc. ReplaceItemValue ( "RiskAssessmentID",riskDoc. UniversalID )
        Call doc. Save ( True, True )
    End If
   
    Call uidoc. Refresh
   
End Sub
To keep the 2 documents in sync we add some code into the PostSave event of the main form:
Sub Postsave (Source As Notesuidocument )
    Dim doc As NotesDocument
    Dim riskDoc As NotesDocument
    Dim db As NotesDatabase
   
    Set doc = source. Document
   
    If doc. RiskAssessmentID ( 0 ) = "" Then
        Return
    End If
   
    Set db = doc. ParentDatabase
    Set riskDoc = db. GetDocumentByUNID (doc. RiskAssessmentID ( 0 ) )
   
    Call riskDoc. ReplaceItemValue ( "Subject",doc. subject )
    'Repeat with other fields needed in views, for workflow and access control
   
    Call riskDoc. Save ( True, True )
   
End Sub
We are almost done. The response documents need some handling when we try to open them.Ideally instead of opening the response we would open the main document. The code in the view's QueryOpenDocument event takes care of that:
Sub Queryopendocument (Source As Notesuiview, Continue As Variant )
    Dim id As String   
    Dim Doc As NotesDocument
    Dim parentDoc As NotesDocument
    Dim db As NotesDatabase
    Dim ws As New NotesUIWorkspace
    Dim s As New NotesSession
   
    id = Source. CaretNoteID
   
    If id = "" Then
        Continue = True
        Exit Sub
    End If
   
    Set db = s. CurrentDatabase
    Set doc = db. GetDocumentByID (id )
   
    If Not doc. IsResponse   Then
        continue = True
        Exit Sub
    End If
   
    continue = False
   
    Set parentDoc = db. GetDocumentByUNID (doc. ParentDocumentUNID )
    Call ws. EditDocument ( False,parentDoc )
   
End Sub
You also need to take care of deletion of documents. Only a user who can see both should be allowed to delete them (or you "flag" them for deletion and let a background agent do the actual deletion). I leave this to you as an exercise. In a real world application you would of course pack all these code into LotusScript objects that live in a ScriptLibrary.
XPages simply woud use 2 data sources and save us the trouble of building a dialog box.
As usual YMMV

Posted by on 04 November 2011 | Comments (1) | categories: Show-N-Tell Thursday

Comments

  1. posted by Karsten Lehmann on Saturday 05 November 2011 AD:
    And you should keep in mind that protecting documents with reader fields do not hide them in any case. With designer access on the database you can create a view, activate the option to show empty categories and use category formulas to get information about the document content. You can even use @DocFields to get a list of item names to find out what to look for.
    IMHO this does not work with personal views, because they get generated and stored on the Notes Client. But "normal views" get created by the indexer which has access to all documents.
    Removing the summary flag from secret items could help. Then they can't show up in views.