diff --git a/docs/diagnostics/FileSystemAccess.md b/docs/diagnostics/FileSystemAccess.md new file mode 100644 index 00000000000..ea11adf570b --- /dev/null +++ b/docs/diagnostics/FileSystemAccess.md @@ -0,0 +1,39 @@ +# Доступ к файловой системе (FileSystemAccess) + + +## Описание диагностики + +При код-ревью или аудите кода необходимо проверять обращения к файлам, каталогам и набор действий, выполняемых с ними, для исключения передачи конфиденциальной или защищенной информации, а также для исключения деструктивных действий с файловой системой. +Важно проверять код от сторонних разработчиков, подрядчиков, из различных интернет-сервисов, каталогов и т.п. + +По найденным замечаниям рекомендуется выполнить ручной аудит кода на предмет его правильности и безопасности. + +## Примеры + +```bsl + Текст = Новый ЧтениеТекста(ПутьФайла, КодировкаТекста.ANSI); // есть замечание + Текст = Новый ЗаписьТекста(ПутьФайла, КодировкаТекста.ANSI); // есть замечание + + ЗначениеВФайл(ПутьФайла, ЛичныеДанные); // есть замечание + КопироватьФайл(ПутьФайла, ДругойПутьФайла); // есть замечание + + МассивИмен = Новый Массив(); + МассивИмен.Добавить(ПутьФайла); + ОбъединитьФайлы(МассивИмен, ДругойПутьФайла); // есть замечание + + ПереместитьФайл(ПутьФайла, ДругойПутьФайла); // есть замечание + РазделитьФайл(ПутьФайла, 1024 * 1024 ); // есть замечание + СоздатьКаталог(ИмяКаталога); // есть замечание + УдалитьФайлы(ПутьФайла); // есть замечание +``` + +## Источники + + +* [Стандарт Доступ к файловой системе из кода конфигурации](https://its.1c.ru/db/v8std#content:542:hdoc) +* [Стандарт Безопасность запуска приложений](https://its.1c.ru/db/v8std#content:774:hdoc) +* [Безопасный режим работы - руководство разработчика](https://its.1c.ru/db/v8323doc#bookmark:dev:TI000000186) diff --git a/docs/en/diagnostics/FileSystemAccess.md b/docs/en/diagnostics/FileSystemAccess.md new file mode 100644 index 00000000000..67b207cf852 --- /dev/null +++ b/docs/en/diagnostics/FileSystemAccess.md @@ -0,0 +1,16 @@ +# FileSystemAccess (FileSystemAccess) + + +## Description + + +## Examples + + +## Sources + + diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FileSystemAccessDiagnostic.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FileSystemAccessDiagnostic.java new file mode 100644 index 00000000000..8dca05a200f --- /dev/null +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FileSystemAccessDiagnostic.java @@ -0,0 +1,121 @@ +/* + * This file is a part of BSL Language Server. + * + * Copyright (c) 2018-2023 + * Alexey Sosnoviy , Nikita Fedkin and contributors + * + * SPDX-License-Identifier: LGPL-3.0-or-later + * + * BSL Language Server is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * BSL Language Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with BSL Language Server. + */ +package com.github._1c_syntax.bsl.languageserver.diagnostics; + +import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticMetadata; +import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticParameter; +import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticScope; +import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticSeverity; +import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticTag; +import com.github._1c_syntax.bsl.languageserver.diagnostics.metadata.DiagnosticType; +import com.github._1c_syntax.bsl.languageserver.utils.bsl.Constructors; +import com.github._1c_syntax.bsl.parser.BSLParser; +import com.github._1c_syntax.utils.CaseInsensitivePattern; +import org.antlr.v4.runtime.tree.ParseTree; + +import java.util.Map; +import java.util.regex.Pattern; + +@DiagnosticMetadata( + type = DiagnosticType.VULNERABILITY, + severity = DiagnosticSeverity.MAJOR, + minutesToFix = 3, + tags = { + DiagnosticTag.SUSPICIOUS + }, + scope = DiagnosticScope.BSL, + activatedByDefault = false +) +public class FileSystemAccessDiagnostic extends AbstractFindMethodDiagnostic { + public static final String NEW_EXPRESSION = "File|Файл|xBase|HTMLWriter|ЗаписьHTML|HTMLReader|ЧтениеHTML" + + "|FastInfosetReader|ЧтениеFastInfoset|FastInfosetWriter|ЗаписьFastInfoset|XSLTransform|ПреобразованиеXSL" + + "|ZipFileWriter|ЗаписьZipФайла|ZipFileReader|ЧтениеZipФайла|TextReader|ЧтениеТекста|TextWriter|ЗаписьТекста" + + "|TextExtraction|ИзвлечениеТекста|BinaryData|ДвоичныеДанные|FileStream|ФайловыйПоток" + + "|FileStreamsManager|МенеджерФайловыхПотоков|DataWriter|ЗаписьДанных|DataReader|ЧтениеДанных"; + + public static final String GLOBAL_METHODS = "ЗначениеВФайл|ValueToFile|КопироватьФайл|FileCopy" + + "|ОбъединитьФайлы|MergeFiles|ПереместитьФайл|MoveFile|РазделитьФайл|SplitFile|СоздатьКаталог|CreateDirectory|" + + "УдалитьФайлы|DeleteFiles|КаталогПрограммы|BinDir|КаталогВременныхФайлов|TempFilesDir" + + "|КаталогДокументов|DocumentsDir|РабочийКаталогДанныхПользователя|UserDataWorkDir" + + "|НачатьПодключениеРасширенияРаботыСФайлами|BeginAttachingFileSystemExtension" + + "|НачатьУстановкуРасширенияРаботыСФайлами|BeginInstallFileSystemExtension" + + "|УстановитьРасширениеРаботыСФайлами|InstallFileSystemExtension" + + "|УстановитьРасширениеРаботыСФайламиАсинх|InstallFileSystemExtensionAsync" + + "|ПодключитьРасширениеРаботыСФайламиАсинх|AttachFileSystemExtensionAsync|" + + "КаталогВременныхФайловАсинх|TempFilesDirAsync|КаталогДокументовАсинх|DocumentsDirAsync" + + "|НачатьПолучениеКаталогаВременныхФайлов|BeginGettingTempFilesDir" + + "|НачатьПолучениеКаталогаДокументов|BeginGettingDocumentsDir" + + "|НачатьПолучениеРабочегоКаталогаДанныхПользователя|BeginGettingUserDataWorkDir" + + "|РабочийКаталогДанныхПользователяАсинх|UserDataWorkDirAsync" + + "|КопироватьФайлАсинх|CopyFileAsync|НайтиФайлыАсинх|FindFilesAsync|НачатьКопированиеФайла|BeginCopyingFile" + + "|НачатьПеремещениеФайла|BeginMovingFile|НачатьПоискФайлов|BeginFindingFiles" + + "|НачатьСозданиеДвоичныхДанныхИзФайла|BeginCreateBinaryDataFromFile" + + "|НачатьСозданиеКаталога|BeginCreatingDirectory" + + "|НачатьУдалениеФайлов|BeginDeletingFiles|ПереместитьФайлАсинх|MoveFileAsync" + + "|СоздатьДвоичныеДанныеИзФайлаАсинх|CreateBinaryDataFromFileAsync|СоздатьКаталогАсинх|CreateDirectoryAsync" + + "|УдалитьФайлыАсинх|DeleteFilesAsync"; + private static final Pattern GLOBAL_METHODS_PATTERN = getPattern(GLOBAL_METHODS); + + @DiagnosticParameter( + type = String.class, + defaultValue = GLOBAL_METHODS + ) + private String globalMethods = GLOBAL_METHODS; + + @DiagnosticParameter( + type = String.class, + defaultValue = NEW_EXPRESSION + ) + private String newExpression = NEW_EXPRESSION; + private Pattern newExpressionPattern = getPattern(newExpression); + + public FileSystemAccessDiagnostic() { + super(GLOBAL_METHODS_PATTERN); + } + + private static Pattern getPattern(String newExpression) { + return CaseInsensitivePattern.compile(newExpression); + } + + @Override + public void configure(Map configuration) { + super.configure(configuration); + setMethodPattern(getPattern(globalMethods)); + newExpressionPattern = getPattern(newExpression); + } + + @Override + protected boolean checkMethodCall(BSLParser.MethodCallContext ctx) { + return false; + } + + @Override + public ParseTree visitNewExpression(BSLParser.NewExpressionContext ctx) { + Constructors.typeName(ctx).ifPresent((String typeName) -> { + var matcherTypeName = newExpressionPattern.matcher(typeName); + if (matcherTypeName.matches()) { + diagnosticStorage.addDiagnostic(ctx); + } + }); + return super.visitNewExpression(ctx); + } +} diff --git a/src/main/resources/com/github/_1c_syntax/bsl/languageserver/configuration/parameters-schema.json b/src/main/resources/com/github/_1c_syntax/bsl/languageserver/configuration/parameters-schema.json index b4e79a4c465..61fbd57d2cd 100644 --- a/src/main/resources/com/github/_1c_syntax/bsl/languageserver/configuration/parameters-schema.json +++ b/src/main/resources/com/github/_1c_syntax/bsl/languageserver/configuration/parameters-schema.json @@ -672,6 +672,16 @@ "title": "No NULL checks for fields from joined tables", "$id": "#/definitions/FieldsFromJoinsWithoutIsNull" }, + "FileSystemAccess": { + "description": "FileSystemAccess", + "default": true, + "type": [ + "boolean", + "object" + ], + "title": "FileSystemAccess", + "$id": "#/definitions/FileSystemAccess" + }, "ForbiddenMetadataName": { "description": "Metadata object has a forbidden name", "default": true, diff --git a/src/main/resources/com/github/_1c_syntax/bsl/languageserver/diagnostics/FileSystemAccessDiagnostic_en.properties b/src/main/resources/com/github/_1c_syntax/bsl/languageserver/diagnostics/FileSystemAccessDiagnostic_en.properties new file mode 100644 index 00000000000..ef44edd4783 --- /dev/null +++ b/src/main/resources/com/github/_1c_syntax/bsl/languageserver/diagnostics/FileSystemAccessDiagnostic_en.properties @@ -0,0 +1,4 @@ +diagnosticMessage=Check access to the file system +diagnosticName=FileSystemAccess +globalMethods=Global methods pattern (regex) +newExpression=Class names pattern (regex) diff --git a/src/main/resources/com/github/_1c_syntax/bsl/languageserver/diagnostics/FileSystemAccessDiagnostic_ru.properties b/src/main/resources/com/github/_1c_syntax/bsl/languageserver/diagnostics/FileSystemAccessDiagnostic_ru.properties new file mode 100644 index 00000000000..73648370051 --- /dev/null +++ b/src/main/resources/com/github/_1c_syntax/bsl/languageserver/diagnostics/FileSystemAccessDiagnostic_ru.properties @@ -0,0 +1,4 @@ +diagnosticMessage=Проверьте обращение к файловой системе +diagnosticName=Доступ к файловой системе +globalMethods=Шаблон глобальных методов (регулярное выражение) +newExpression=Шаблон классов (регулярное выражение) diff --git a/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FileSystemAccessDiagnosticTest.java b/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FileSystemAccessDiagnosticTest.java new file mode 100644 index 00000000000..e12905ee47f --- /dev/null +++ b/src/test/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/FileSystemAccessDiagnosticTest.java @@ -0,0 +1,87 @@ +/* + * This file is a part of BSL Language Server. + * + * Copyright (c) 2018-2023 + * Alexey Sosnoviy , Nikita Fedkin and contributors + * + * SPDX-License-Identifier: LGPL-3.0-or-later + * + * BSL Language Server is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * BSL Language Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with BSL Language Server. + */ +package com.github._1c_syntax.bsl.languageserver.diagnostics; + +import org.eclipse.lsp4j.Diagnostic; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; + +import static com.github._1c_syntax.bsl.languageserver.util.Assertions.assertThat; + +class FileSystemAccessDiagnosticTest extends AbstractDiagnosticTest { + FileSystemAccessDiagnosticTest() { + super(FileSystemAccessDiagnostic.class); + } + + @Test + void test() { + + List diagnostics = getDiagnostics(); + + assertThat(diagnostics, true) + .hasRange(1, 15, 35) + .hasRange(2, 15, 41) + .hasRange(3, 15, 31) + .hasRange(4, 15, 31) + .hasRange(5, 15, 38) + .hasRange(6, 15, 38) + .hasRange(7, 15, 33) + .hasRange(8, 15, 44) + .hasRange(9, 15, 44) + .hasRange(10, 15, 41) + .hasRange(11, 15, 41) + .hasRange(12, 15, 45) + .hasRange(13, 15, 41) + .hasRange(14, 15, 56) + .hasRange(19, 15, 41) + .hasRange(24, 15, 26) + + .hasRange(29, 4, 17) + .hasRange(30, 4, 18) + .hasRange(34, 4, 19) + .hasRange(36, 4, 19) + .hasRange(37, 4, 17) + .hasRange(38, 4, 18) + .hasRange(39, 4, 16) + .hasSize(23) + ; + } + + @Test + void testConfigure() { + + Map configuration = diagnosticInstance.info.getDefaultConfiguration(); + configuration.put("globalMethods", "ЗначениеВФайл"); + configuration.put("newExpression", "File"); + diagnosticInstance.configure(configuration); + + List diagnostics = getDiagnostics(); + + assertThat(diagnostics, true) + .hasRange(1, 15, 35) + .hasRange(29, 4, 17) + .hasSize(2); + } + +} diff --git a/src/test/resources/diagnostics/FileSystemAccessDiagnostic.bsl b/src/test/resources/diagnostics/FileSystemAccessDiagnostic.bsl new file mode 100644 index 00000000000..84333a26b2c --- /dev/null +++ b/src/test/resources/diagnostics/FileSystemAccessDiagnostic.bsl @@ -0,0 +1,41 @@ +Процедура Метод1() + Значение = Новый File(ИмяФайла); // есть ошибка + Значение = Новый xBase("C:\temp.dbf"); // есть ошибка + Значение = Новый HTMLWriter; // есть ошибка + Значение = Новый HTMLReader; // есть ошибка + Значение = Новый FastInfosetReader; // есть ошибка + Значение = Новый FastInfosetWriter; // есть ошибка + Значение = Новый XSLTransform; // есть ошибка + Значение = Новый ZipFileWriter(ИмяФайла); // есть ошибка + Значение = Новый ZipFileReader(ИмяФайла); // есть ошибка + Значение = Новый TextReader(ИмяФайла); // есть ошибка + Значение = Новый TextWriter(ИмяФайла); // есть ошибка + Значение = Новый TextExtraction(ИмяФайла); // есть ошибка + Значение = Новый BinaryData(ИмяФайла); // есть ошибка + Значение = Новый FileStream(ИмяФайла, РежимОткрытия); // есть ошибка +КонецПроцедуры + +&НаСервере +Процедура Метод2() + Значение = Новый xBase("C:\temp.dbf"); // есть ошибка +КонецПроцедуры + +&НаСервереБезКонтекста +Процедура Метод3() + Значение = Новый xBase; // есть ошибка +КонецПроцедуры + +&НаКлиенте +Процедура Метод4() + ЗначениеВФайл("C:\Temp\PersonalData.txt", ЛичныеДанные); // есть ошибка + КопироватьФайл("C:\Temp\Order.htm", "C:\My Documents\Order.htm"); // есть ошибка + + МассивИмен = Новый Массив(); + МассивИмен.Добавить("C:\Windows\Temp\Presentation.ppt.1"); + ОбъединитьФайлы(МассивИмен, "C:\Windows\Temp\Presentation.ppt"); // есть ошибка + + ПереместитьФайл("C:\Temp\Order.htm", "C:\My Documents\Order.htm"); // есть ошибка + РазделитьФайл("C:\Windows\Temp\Presentation.ppt", 1024 * 1024 ); // есть ошибка + СоздатьКаталог("C:\Temp"); // есть ошибка + УдалитьФайлы("C:\temp\Works"); // есть ошибка +КонецПроцедуры