11# Security Filters
22
3+ This document provides some guidance about how to organize your documents in
4+ order to secure your data, e.g. making sure users can access only data
5+ meant to be accessible to them.
6+
37Semantic Memory allows to organize memories with two main approaches, which
48can also be used together for maximum flexibility.
59
@@ -27,16 +31,22 @@ to each document a User ID tag that your application can filter by.
2731
2832** Vector DBs like Azure Cognitive Search, Qdrant, Pinecone, etc. don't offer
2933document-level permissions** and search results can't vary by user.
30- Documents stored in Vector DBs though can be decorated with metadata and can
31- be filtered when searching, applying some filters.
34+ Vector storages are optimized to store large quantity of documents indexed
35+ using embedding vectors, and to quickly find similar documents.
36+ Vector records stored in Vector DBs though can be decorated with metadata, and
37+ can be filtered when searching, applying some logical filters.
38+
39+ Semantic Memory leverages this capability, and uses specific native filters
40+ on all the supported Vector DBs (Azure Cognitive Search, Qdrant, etc), removing
41+ the need to learn ad-hoc filtering syntax, allowing to ** tag every memory
42+ during the ingestion** , and allowing to ** filter by tag when searching** ,
43+ during the retrieval process.
3244
33- Semantic Memory makes this transparent regardless of the vector DB selected,
34- allowing to ** tag every memory during the ingestion ** , and allowing to ** filter
35- by tag when searching ** , during the retrieval process .
45+ Tags are free and customizable. Multiple tags can be used and each tag can
46+ have multiple values. Tags can be used to filter by user, by type, etc. and
47+ in particular can be leveraged for your security scenarios .
3648
37- Tags are completely free and customizable. Multiple tags can be used and each
38- tag can have multiple values, so you can create your custom security filters.
39- Here's some example scenarios:
49+ Here's some examples:
4050
4151* Use a "userID" tag to restrict records to one or multiple users.
4252* Use a "userEmail" tag to restrict records using the user email address.
@@ -52,10 +62,10 @@ cascade deletions, etc.
5262> so you should consider these two important points:
5363>
5464> 1 . Memories stored without tags are visible only when searching without
55- > filters, e.g. they are visible to all users.
56- > 2 . Searching without filters searches the entire index. If you are using tags
57- > as security filters, ** you should always filter by tags when retrieving**
58- > information.
65+ > filters, e.g. they are visible to all users.
66+ > 2 . Searching without filters searches the entire index. If you are using tags
67+ > as security filters, ** you should always filter by tags when retrieving**
68+ > information.
5969
6070## Code examples
6171
@@ -65,8 +75,10 @@ Simple file upload, without tags or explicit index name. The associated
6575memory records can't be filterable and are stored in the default index.
6676
6777``` csharp
78+ // Upload a file into memory. This file has no tags.
6879var docId = await memory .ImportDocumentAsync (" project.docx" );
69-
80+
81+ // Ask a question, without tags. This will search the entire index.
7082var answer = await memory .AskAsync (" what's the project timeline?" );
7183```
7284
@@ -75,6 +87,7 @@ memory records can't be filtered by tags, but are isolated in a dedicated
7587index.
7688
7789``` csharp
90+ // Upload a file in a specific index.
7891var docId = await memory .ImportDocumentAsync (" project.docx" , index : " index001" );
7992
8093// NO ANSWER: the data is not in the default index
@@ -84,6 +97,13 @@ var answer = await memory.AskAsync("what's the project timeline?");
8497var answer = await memory .AskAsync (" what's the project timeline?" , index : " index001" );
8598```
8699
100+ ### Security Filters
101+
102+ These examples use the ` user ` tag to secure data retrieval, making sure the
103+ current user can see only data tagged by their user ID.
104+
105+ #### Example 1
106+
87107File upload with a ` user ` tag. The associated memory records can be filtered
88108using the ` user ` tag.
89109
@@ -92,67 +112,109 @@ a filter**.
92112
93113``` csharp
94114var docId = await memory .ImportDocumentAsync (new Document ()
95- .AddFile (" project.docx" )
96- .AddTag (" user" , " USER-333" ));
115+ .AddFile (" project.docx" )
116+ .AddTag (" user" , " USER-333" ));
97117
98118// OK
99119var answer = await memory .AskAsync (" what's the project timeline?" );
100120
101121// OK
102- var answer = await memory .AskAsync (" what's the project timeline?" , MemoryFilters .ByTag (" user" , " USER-333" ));
122+ var answer = await memory .AskAsync (" what's the project timeline?" ,
123+ MemoryFilters .ByTag (" user" , " USER-333" ));
103124
104- // NO ANSWER: memories are tagged with 'USER-333', so filter 'USER-444' will not match the information extracted from project.docs
105- var answer = await memory .AskAsync (" what's the project timeline?" , MemoryFilters .ByTag (" user" , " USER-444" ));
125+ // NO ANSWER: memories are tagged with 'USER-333', so filter 'USER-444'
126+ // will not match the information extracted from project.docs
127+ var answer = await memory .AskAsync (" what's the project timeline?" ,
128+ MemoryFilters .ByTag (" user" , " USER-444" ));
106129```
107130
131+ #### Example 2
132+
108133Very similar to previous example, using a specific index.
109134
110135``` csharp
136+ // Upload a document in specific user and tag with user ID.
111137var docId = await memory .ImportDocumentAsync (new Document ()
112- .AddFile (" project.docx" )
113- .AddTag (" user" , " USER-333" ),
114- index : " index002" );
138+ .AddFile (" project.docx" )
139+ .AddTag (" user" , " USER-333" ),
140+ index : " index002" );
115141
116142// NO ANSWER: the data is not in the default index
117143var answer = await memory .AskAsync (" what's the project timeline?" );
118144
119- // NO ANSWER: the data is not in the default index
120- var answer = await memory .AskAsync (" what's the project timeline?" , MemoryFilters .ByTag (" user" , " USER-333" ));
145+ // NO ANSWER: even if the filter is correct, the data is not in the default index
146+ var answer = await memory .AskAsync (" what's the project timeline?" ,
147+ MemoryFilters .ByTag (" user" , " USER-333" ));
121148
122149// OK
123- var answer = await memory .AskAsync (" what's the project timeline?" , MemoryFilters .ByTag (" user" , " USER-333" ), index : " index002" );
150+ var answer = await memory .AskAsync (" what's the project timeline?" ,
151+ MemoryFilters .ByTag (" user" , " USER-333" ),
152+ index : " index002" );
153+
154+ // IMPORTANT: this command is missing the user tag and the service will return the data.
155+ // This is equivalent to an admin having full access.
156+ var answer = await memory .AskAsync (" what's the project timeline?" ,
157+ index : " index002" );
124158```
125159
160+ #### Example 3
161+
126162Example showing how to apply multiple tags, even for the same tag name.
127- E.g. in this case the document information is tagged with two user IDs,
163+
164+ In this case the document information is tagged with two user IDs,
128165so both users can ask for questions.
129166
130167``` csharp
168+ // Upload file, allow two users to access
131169var docId = await memory .ImportDocumentAsync (new Document ()
132- .AddFile (" project.docx" )
133- .AddTag (" user" , " USER-333" )
134- .AddTag (" user" , " USER-444" ));
170+ .AddFile (" project.docx" )
171+ .AddTag (" user" , " USER-333" )
172+ .AddTag (" user" , " USER-444" ));
135173
136- // OK
137- var answer = await memory .AskAsync (" what's the project timeline?" , MemoryFilters .ByTag (" user" , " USER-333" ));
174+ // OK: USER-333 tag matches
175+ var answer = await memory .AskAsync (" what's the project timeline?" ,
176+ MemoryFilters .ByTag (" user" , " USER-333" ));
138177
139- // OK
140- var answer = await memory .AskAsync (" what's the project timeline?" , MemoryFilters .ByTag (" user" , " USER-444" ));
178+ // OK: USER-444 tag matches
179+ var answer = await memory .AskAsync (" what's the project timeline?" ,
180+ MemoryFilters .ByTag (" user" , " USER-444" ));
141181```
142182
183+ #### Example 4
184+
143185Finally , tags can be used also for categorizing data:
144186
145187``` csharp
188+ // Upload file, allow two users to access, and add a content type tag for extra filtering
146189var docId = await memory .ImportDocumentAsync (new Document ()
147- .AddFile (" project.docx" )
148- .AddTag (" user" , " USER-333" )
149- .AddTag (" user" , " USER-444" )
150- .AddTag (" type" , " planning" ));
190+ .AddFile (" project.docx" )
191+ .AddTag (" user" , " USER-333" )
192+ .AddTag (" user" , " USER-444" )
193+ .AddTag (" type" , " planning" ));
151194
152195// No information found, the type tag doesn't match
153- var answer = await memory .AskAsync (" what's the project timeline?" , MemoryFilters .ByTag (" user" , " USER-333" ).ByTag (" type" , " email" ));
196+ var answer = await memory .AskAsync (" what's the project timeline?" ,
197+ MemoryFilters .ByTag (" user" , " USER-333" )
198+ .ByTag (" type" , " email" ));
154199
155200// OK
156- var answer = await memory .AskAsync (" what's the project timeline?" , MemoryFilters .ByTag (" user" , " USER-333" ).ByTag (" type" , " planning" ));
201+ var answer = await memory .AskAsync (" what's the project timeline?" ,
202+ MemoryFilters .ByTag (" user" , " USER-333" )
203+ .ByTag (" type" , " planning" ));
204+
205+ ```
206+
207+ # Security best practices
208+
209+ Summarizing, we recommend these best practices to secure Semantic Memory usage:
157210
158- ```
211+ * Use Semantic Memory as ** a private backend component** , similar to a SQL
212+ Server, without granting direct access. When using Semantic Memory as a
213+ service, consider assigning the service a reserved IP, accessible only to
214+ your IP, and using HTTPS only.
215+ * Authenticate users in your backend using a secure solution like Azure
216+ Active Directory, extract the user ID from the signed credentials like JWT
217+ tokens or client certs, and tag every interaction with Semantic Memory with
218+ this User ID
219+ * ** Use Semantic Memory Tags as Security Filters** . Make sure every API call
220+ to Semantic Memory uses a User tag, both when reading and writing to memory.
0 commit comments